Skip to content

Conversation

@superg
Copy link
Owner

@superg superg commented Nov 27, 2025

WIP

Summary by CodeRabbit

  • New Features

    • Unified DVD dumping with improved Xbox/Kreon handling, protection-aware skip/write behavior, and new Xbox security/context utilities.
    • New array-based endian conversion helpers.
  • Bug Fixes

    • Stronger range handling with automatic merging and stricter validation/error behavior.
    • Improved read/write error reporting, retries and fallback behavior; refined security-sector handling.
  • Tests

    • Added comprehensive range tests covering merges, boundaries, and edge cases.
  • Chores

    • Updated drive metadata, generalized range/string parsing, module reorganization, and increased CI verbosity.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Walkthrough

Range insertion now throws on invalid input and merges overlaps; string_to_ranges was templatized. Xbox utilities moved into a new dvd.xbox module exposing a Context-based security-layer API. DVD dump/split flows were refactored to use protection ranges, FORM1_DATA_SIZE, and expanded Kreon handling; tests and endian utilities were extended.

Changes

Cohort / File(s) Summary
Range core & tests
\range.ixx`, `tests/tests.cc`, `tests/CMakeLists.txt``
insert_range signature changed boolvoid and now throws via throw_line on invalid input; overlapping/adjacent ranges are merged. Added test_range() and included range.ixx in test build.
Range callers (cd tools & dumps)
\cd/cd_common.ixx`, `cd/cd_dump.ixx`, `cd/cd_split.ixx``
Call sites updated to remove caller-side exception paths; some now pass explicitly-typed string_to_ranges<int32_t> results.
String parsing templating
\utils/strings.ixx`, callers: `cd/`, `dvd/``
string_to_ranges converted to template<typename T> returning std::vector<std::pair<T,T>> with unsigned-type checks; ranges_to_string removed. Callers adjusted for templated return type.
Xbox / security rewrite & module move
\utils/xbox.ixx` → `dvd/xbox.ixx`, `dvd/dvd_dump.ixx`, `dvd/dvd_split.ixx`, `debug.ixx``
Xbox functionality moved to dvd.xbox (namespace gpsxre::xbox) introducing Context, SecurityLayerDescriptor, read/clean/merge helpers, initialize(...) that returns a Context. Dump/split and debug updated to use the new module.
DVD dumping & split behavior
\dvd/dvd_dump.ixx`, `dvd/dvd_split.ixx``
redumper_dump_dvd renamed parameter dump_mode; dump flow refactored to protection-range-driven skip/write decisions, added Kreon detection/early-unlock/final-unlock, unified sector counting, and replaced DVD_DESCRIPTOR_SIZE with FORM1_DATA_SIZE.
Drive database & helpers
\drive.ixx``
DRIVE_DATABASE entries updated (offsets, revisions, type classifications); added exported helpers is_kreon_firmware(const DriveConfig&) and is_custom_kreon_firmware(const DriveConfig&).
Endian utilities
\utils/endian.ixx``
Added exported templates endian_swap_from_array and endian_swap_to_array; included <climits>; explicit specializations are no longer exported.
Module & build edits
\CMakeLists.txt`, `.github/workflows/cmake.yml``
Moved Xbox source from utils/xbox.ixx to dvd/xbox.ixx in build sources; added verbose ctest flags in CI steps.
Minor edits
\scsi/cmd.ixx`, `rom_entry.ixx`, `debug.ixx``
Simplified conditional in cmd_kreon_set_lock_state; added ~ROMEntry() = default;; added inert debug block guarded by if(0) and imported dvd.xbox.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as Options/Client
    participant Dump as redumper_dump_dvd
    participant Ranges as range module
    participant Xbox as dvd::xbox::initialize
    participant Drive as SPTD / Drive

    CLI->>Dump: start dump (options, skip string)
    Dump->>Ranges: string_to_ranges<T>(options.skip)
    Ranges-->>Dump: protection ranges (std::vector<Range<uint32_t>>)
    Dump->>Xbox: initialize(protection, sptd, layer0, capacity, ...)
    Xbox->>Drive: read_security_layer_descriptor / read sectors
    Drive-->>Xbox: security descriptor / sector data
    Xbox-->>Dump: Context (security_sector, lock_sector_start, layer1_video_start)
    loop per-sector
        Dump->>Ranges: is sector in protection ranges?
        alt protected
            Dump->>Drive: read sector (skip storing)
        else unprotected
            Dump->>Drive: read sector (store/write)
        end
    end
    Dump->>Xbox: finalize (unlock/cleanup)
    Dump-->>CLI: finish (result/logs)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–60 minutes

  • Review focus:
    • range.ixx — exception semantics, merge correctness, API change impact on all call sites.
    • dvd/xbox.ixx — large public API surface, binary layout of SecurityLayerDescriptor, ownership/lifetime of Context data, and side effects during initialize().
    • dvd/dvd_dump.ixx & dvd/dvd_split.ixx — integration with protection ranges, Kreon flows, and FORM1_DATA_SIZE substitution.
    • utils/strings.ixx — templated parsing correctness for signed/unsigned types and updated call-sites.

Possibly related PRs

  • new drive added #299 — also modifies drive.ixx DRIVE_DATABASE entries; likely related to the drive metadata updates in this PR.

Poem

🐇 I hop through ranges, stitch them tight,
Merging edges by moonlit byte.
Xbox Context cradles secret thread,
Kreon gates opened, then gently spread.
Tests blink green — a bunny’s delight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Dvd iso volume size' is vague and does not clearly convey the scope of changes. The PR actually involves extensive refactoring across multiple modules including Xbox/Kreon firmware handling, protection ranges, range merging logic, and security sector operations—far beyond ISO volume size. Revise the title to reflect the primary objective of the changeset, such as 'Add Xbox/Kreon support and protection-based range handling for DVD dumping' or a more specific phrase capturing the main architectural changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dvd_iso_volume_size

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
drive.ixx (1)

404-414: LGTM! Minor suggestion: consider documenting the distinction between these predicates.

The implementation is correct. Both functions serve different purposes:

  • is_kreon_firmware: Detects drives with Kreon firmware via vendor-specific string
  • is_custom_kreon_firmware: Detects specific patched revision levels ("DC02", "ZZ01")

Note that "DC02" doesn't appear in the current DRIVE_DATABASE entries—verify this is intentional for drives expected in the wild but not yet catalogued.

Consider extracting magic strings as constants for maintainability:

+static constexpr std::string_view KREON_FIRMWARE_PREFIX = "KREON V1.00";
+static constexpr std::string_view KREON_REVISION_DC02 = "DC02";
+static constexpr std::string_view KREON_REVISION_ZZ01 = "ZZ01";
+
 export bool is_kreon_firmware(const DriveConfig &drive_config)
 {
-    return drive_config.vendor_specific.starts_with("KREON V1.00");
+    return drive_config.vendor_specific.starts_with(KREON_FIRMWARE_PREFIX);
 }


 export bool is_custom_kreon_firmware(const DriveConfig &drive_config)
 {
-    return drive_config.product_revision_level == "DC02" || drive_config.product_revision_level == "ZZ01";
+    return drive_config.product_revision_level == KREON_REVISION_DC02 || drive_config.product_revision_level == KREON_REVISION_ZZ01;
 }
debug.ixx (1)

24-145: Xbox debug block is inert but grows debug.ixx surface

The new import dvd.xbox; and if(0) block are debug-only and currently have no runtime effect, which is fine. If this code becomes something you rely on regularly, consider promoting it to a named helper or toggling it via a flag instead of hardcoded if(0) to keep redumper_debug maintainable.

range.ixx (1)

1-6: Verify throw_line header path

This file includes "utils/throw_line.hh", while other modules include "throw_line.hh". Please confirm that this path is valid in your include layout; otherwise, align it with the existing includes to avoid build issues.

dvd/dvd_dump.ixx (1)

681-690: Minor optimization opportunity: cache find_range result.

find_range(protection, s) is called twice - once in the loop condition and once for comparison. Consider caching the result:

auto base_range = find_range(protection, s);
for(uint32_t i = 0; i < sectors_to_read; ++i)
{
    if(base_range != find_range(protection, s + i))
    {
        sectors_to_read = i;
        break;
    }
}
utils/xbox.ixx (1)

207-216: Clarify complex condition with parentheses.

The condition on line 209 relies on operator precedence (&& before ||). Adding explicit parentheses would improve readability:

-        if(xgd_version(layer0_last) == 1 && i >= 16 || xgd_version(layer0_last) != 1 && i != 0 && i != 3)
+        if((xgd_version(layer0_last) == 1 && i >= 16) || (xgd_version(layer0_last) != 1 && i != 0 && i != 3))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 908b93e and 6c69b88.

📒 Files selected for processing (14)
  • cd/cd_common.ixx (1 hunks)
  • cd/cd_dump.ixx (1 hunks)
  • cd/cd_split.ixx (1 hunks)
  • debug.ixx (2 hunks)
  • drive.ixx (2 hunks)
  • dvd/dvd_dump.ixx (11 hunks)
  • dvd/dvd_split.ixx (4 hunks)
  • range.ixx (2 hunks)
  • scsi/cmd.ixx (1 hunks)
  • tests/CMakeLists.txt (1 hunks)
  • tests/tests.cc (3 hunks)
  • utils/endian.ixx (2 hunks)
  • utils/strings.ixx (2 hunks)
  • utils/xbox.ixx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-07T19:05:32.220Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/cmd.ixx:558-571
Timestamp: 2025-09-07T19:05:32.220Z
Learning: In the scsi/cmd.ixx file, there are multiple functions that use pointer-byte indexing for endianness conversion that could be prone to endianness issues. The maintainer prefers to address these systematically in a centralized manner rather than piecemeal fixes.

Applied to files:

  • scsi/cmd.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-windows (arm64, ARM64)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
🔇 Additional comments (27)
drive.ixx (2)

130-176: LGTM on DRIVE_DATABASE updates.

The database entries are well-structured with consistent offset, revision, and type classifications. The addition of the "PATCHED KREON" comment on line 175 improves clarity for distinguishing Kreon-specific firmware entries.


183-211: LGTM on remaining database entries.

The legacy PLEXTOR drives and OTHER section entries are consistently formatted with appropriate type classifications and sector order configurations.

utils/endian.ixx (1)

4-4: LGTM!

The <climits> include is necessary for CHAR_BIT used in the new template functions.

scsi/cmd.ixx (1)

513-531: Lock-state branch simplification is safe

Using if(lock_state == KREON_LockState::LEGACY) instead of an intermediate boolean preserves the original behavior and improves readability; no issues found.

cd/cd_common.ixx (1)

694-705: Protection range insertion correctly delegates validation to insert_range

Switching to unconditional insert_range calls and dropping explicit failure handling is consistent with the new API where insert_range throws on invalid ranges and merges overlaps itself; no further changes needed here.

range.ixx (1)

56-82: insert_range merge/validation semantics look correct

The new insert_range:

  • Rejects invalid ranges via throw_line, centralizing validation.
  • Correctly finds and merges all overlapping or adjacent intervals, maintaining sorted, non-overlapping ranges.
    This matches the behavior exercised in test_range() and aligns with callers now ignoring a return value.
tests/CMakeLists.txt (1)

13-13: Including range.ixx in the tests target is correct

Adding range.ixx to the tests module set matches the new import range; in tests.cc and is required for the range tests to compile.

cd/cd_dump.ixx (1)

281-286: Session gap handling via insert_range is consistent with new API

Using insert_range(session_gaps, r); without checking a return value is appropriate now that insert_range validates and merges ranges internally; this keeps the gap logic simpler and leverages the shared range semantics.

tests/tests.cc (1)

14-457: Range tests give good coverage of the new insert_range semantics

import range; plus test_range() exercise:

  • Non-overlapping insertion and ordering,
  • find_range lookup correctness,
  • Overlapping and adjacent range merges,
  • Insertions inside existing ranges,
  • Exception behavior on invalid ranges,
  • Edge insertions at start/end of the set.

This should catch most regressions in the range module; no issues spotted.

dvd/dvd_split.ixx (3)

12-21: LGTM! Import updates align with module refactoring.

The imports correctly reflect the module rename (dvd.xbox) and the addition of the range module for Range<uint32_t> support.


48-54: LGTM! Consistent use of FORM1_DATA_SIZE.

The manufacturer file size check (FORM1_DATA_SIZE + 4) and ROM entry update correctly account for the 4-byte header that gets trimmed.


103-117: LGTM! Clean refactoring to use xbox namespace and Range type.

The security sector processing correctly uses the new xbox::clean_security_sector and xbox::get_security_layer_descriptor_ranges APIs. The range logging with r.end - 1 properly converts the exclusive end to an inclusive display format.

utils/strings.ixx (1)

304-335: Approve templated string_to_ranges with a note on potential edge case.

The template generalization is well-implemented with proper unsigned validation. The range storage semantics (exclusive end via end + 1) are consistent.

However, if end equals std::numeric_limits<T>::max(), the (T)end + 1 expression on line 331 will overflow/wrap to zero. This is unlikely in practice for sector ranges but worth noting.

Consider whether the input validation should guard against end == std::numeric_limits<T>::max() to prevent wraparound, or document this as a precondition.

dvd/dvd_dump.ixx (8)

379-381: LGTM! Protection range initialization.

Correct use of the templated string_to_ranges<uint32_t> and insert_range to build the protection ranges vector.


383-392: LGTM! Early Kreon unlock for accurate capacity reading.

The early unlock ensures READ_CAPACITY returns the correct value for Xbox disc detection. The non-fatal error handling allows graceful fallback.


394-404: LGTM! Capacity querying with block size validation.

The capacity read and block size validation are correct. Using a scoped block keeps variables contained.


424-467: LGTM! Xbox context initialization and security sector handling.

The Xbox detection logic, security sector storage/comparison for disc verification during refine, and fallback for malformed XGD are well-structured.


469-480: LGTM! Physical sector count calculation.

Correctly accumulates layer lengths across all physical structures using optional semantics.


734-772: LGTM! Protection range handling.

Sectors within protection ranges are correctly marked for storage without reading, resulting in zeroed sectors in the output. The SCSI error handling with retry logic for refine mode is properly implemented.


845-851: LGTM! Kreon drive cleanup.

Properly re-unlocks the drive at the end of the dump if it was locked, ensuring the drive is left in a usable state.


642-649: LGTM! Sectors count determination logic.

Correctly prioritizes physical structure sector count over capacity, with appropriate warning for mismatches outside Xbox context.

utils/xbox.ixx (6)

26-31: LGTM! Context struct design.

Clean encapsulation of Xbox-related state for passing between dump functions.


34-136: LGTM! Well-documented SecurityLayerDescriptor union.

The packed union with documented byte offsets provides clean access to XGD security sector data. The structure handles XGD1/2/3 variants appropriately.


139-162: LGTM! PSN/LBA conversion and version detection.

The PSN-to-LBA conversion correctly handles the 0x30000 offset and layer wrap-around for opposite track path. Version detection via layer0_last values is clean.


220-244: LGTM! Security sector cleaning for consistent comparison.

Correctly normalizes challenge-response data for XGD2/XGD3 to enable consistent security sector comparison across dumps.


247-306: LGTM! Xbox initialization with XGD3 repair support.

The initialize function correctly handles XGD detection, optional XGD3 security sector repair via leadout, and computes the necessary offsets for Kreon lock/unlock. The modification of layer0_ld is documented.

One note: read_security_layer_descriptor can throw, which will propagate up. This is appropriate for initialization failure.


187-198: LGTM! XGD3 security sector merge/repair logic.

Correctly transfers the necessary fields from Kreon-read SS to leadout SS to produce a valid XGD3 security sector.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
dvd/dvd_dump.ixx (3)

434-468: Consider extracting Xbox initialization logic to a helper function.

The Xbox/Kreon detection and security sector handling is deeply nested (6+ levels) and spans 30+ lines. Extracting this to a helper function like try_initialize_xbox_context(...) would improve readability and testability.


470-481: Consider simplifying sectors_count_physical accumulation.

The current pattern of checking !sectors_count_physical, initializing to 0, then dereferencing works but is verbose. Consider using value_or():

-            for(uint32_t i = 0; i < physical_structures.size(); ++i)
-            {
-                auto const &structure = physical_structures[i];
-
-                auto &layer_descriptor = (READ_DVD_STRUCTURE_LayerDescriptor &)structure[sizeof(CMD_ParameterListHeader)];
-
-                if(!sectors_count_physical)
-                    sectors_count_physical = 0;
-
-                *sectors_count_physical = *sectors_count_physical + get_layer_length(layer_descriptor);
-            }
+            for(uint32_t i = 0; i < physical_structures.size(); ++i)
+            {
+                auto const &structure = physical_structures[i];
+
+                auto &layer_descriptor = (READ_DVD_STRUCTURE_LayerDescriptor &)structure[sizeof(CMD_ParameterListHeader)];
+
+                sectors_count_physical = sectors_count_physical.value_or(0) + get_layer_length(layer_descriptor);
+            }

693-711: Consider extracting Xbox/Kreon locking logic to a helper function.

The Xbox-specific sector adjustment and Kreon locking logic adds complexity to the main read loop. Extracting this to a helper function like handle_xbox_sector_adjustment(...) would improve readability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c69b88 and 03e762b.

📒 Files selected for processing (3)
  • dvd/dvd_dump.ixx (11 hunks)
  • rom_entry.ixx (1 hunks)
  • utils/endian.ixx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • utils/endian.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-windows (arm64, ARM64)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
🔇 Additional comments (14)
rom_entry.ixx (1)

30-31: Defaulted destructor is safe but likely optional.

The defaulted destructor is appropriate for this class, as all members are value types or standard library types that manage their own cleanup. This addition is fine, though it may be unnecessary unless required by a coding standard or style guide.

dvd/dvd_dump.ixx (13)

5-6: LGTM!

The new includes and imports appropriately support the Xbox context management, optional physical sector counts, and protection range functionality introduced in this PR.

Also applies to: 9-9, 18-18, 21-21


384-393: LGTM!

The early Kreon unlock logic is well-motivated by the comment and appropriately handles errors with logging rather than throwing, allowing the operation to continue if the unlock fails.


395-405: LGTM!

The capacity reading refactor clearly separates this logic and correctly validates the block size against FORM1_DATA_SIZE. The calculation sector_last + 1 is correct for converting the 0-indexed last sector address to a total count.


411-413: LGTM!

The use of std::shared_ptr for the Xbox context and std::optional for the physical sector count appropriately models the conditional nature of these values.


428-431: LGTM!

Good defensive validation of physical structure sizes before accessing layer descriptors. The error message includes the layer index for debugging.


486-502: LGTM!

The indexed suffix logic cleanly handles both single and multi-layer disc structures, creating filenames like .manufacturer.0, .manufacturer.1 for multi-layer discs and .manufacturer for single-layer discs.


565-567: LGTM!

The reference cast style is consistent with the new approach used earlier in the function and is safe due to the size validation performed at lines 428-431.


643-650: LGTM!

The sector count determination logic correctly prioritizes physical structure counts and appropriately warns on mismatches only for non-Xbox discs, where such discrepancies are unexpected.


683-691: LGTM!

The protection range boundary checking ensures that read operations don't span across different ranges (skip vs. non-skip), which is essential for correct handling. The pointer comparison in find_range(protection, s) != find_range(protection, s + i) correctly identifies range transitions.


735-773: LGTM!

The protection-based read path correctly skips sectors in protected ranges and handles errors with detailed logging. The conditional retry information in verbose mode (lines 747-752) is particularly helpful for debugging.


832-834: LGTM!

Correctly conditions ROM entry updates on dump mode and absence of errors, ensuring hash calculations only include successfully read data.


846-852: LGTM!

The Kreon re-unlock logic appropriately restores the drive state at the end of the operation. Error logging without throwing is correct for cleanup code, ensuring the function completes even if the unlock fails.


380-383: Error handling for invalid skip ranges is already appropriately implemented.

The code provides user-friendly error messages through two validation layers:

  1. string_to_ranges (utils/strings.ixx): Validates input format and throws "negative value not allowed for unsigned range type ({value})" with the actual problematic value.

  2. insert_range (range.ixx): Validates range structure and throws "insertion failed, invalid range configuration: [{start}, {end}]" with actual values when start >= end.

Both use throw_line, which wraps std::runtime_error with formatted messages that reach users. This error-handling pattern is consistent with other validation in the redumper_dump_dvd function and appropriately catches user configuration errors early.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/tests.cc (2)

402-416: Test 9 is identical to Test 1.

Both tests insert ranges {10,20}, {30,40}, {50,60} and verify 3 non-overlapping ranges with the same assertions. Consider either removing this duplicate or modifying it to specifically test appending to the end by inserting ranges in a different order (e.g., insert {50,60} last after {10,20} and {30,40} are already present).

     // Test 9: Insert at end without overlap
     ranges.clear();
     std::cout << "Test 9: Insert at end without overlap... " << std::flush;
     insert_range(ranges, Range<int32_t>{ 10, 20 });
     insert_range(ranges, Range<int32_t>{ 30, 40 });
-    insert_range(ranges, Range<int32_t>{ 50, 60 });
+    insert_range(ranges, Range<int32_t>{ 70, 80 });  // Append beyond existing ranges
-    if(ranges.size() == 3 && ranges[0].start == 10 && ranges[0].end == 20 && ranges[1].start == 30 && ranges[1].end == 40 && ranges[2].start == 50 && ranges[2].end == 60)
+    if(ranges.size() == 3 && ranges[0].start == 10 && ranges[0].end == 20 && ranges[1].start == 30 && ranges[1].end == 40 && ranges[2].start == 70 && ranges[2].end == 80)

277-280: Consider adding edge case tests for invalid ranges.

The test suite covers happy-path scenarios well. Based on the range module changes, consider adding tests for:

  1. Invalid ranges where start > end (should throw per the new behavior)
  2. Empty ranges where start == end (boundary behavior)

Example test for exception on invalid range:

// Test: Invalid range should throw
std::cout << "Test: Invalid range (start > end) should throw... " << std::flush;
try {
    std::vector<Range<int32_t>> temp;
    insert_range(temp, Range<int32_t>{ 30, 10 });
    std::cout << "failure (no exception thrown)" << std::endl;
    success = false;
} catch (...) {
    std::cout << "success" << std::endl;
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 579d35f and 8c36d79.

📒 Files selected for processing (1)
  • tests/tests.cc (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-windows (arm64, ARM64)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
🔇 Additional comments (3)
tests/tests.cc (3)

14-14: LGTM!

Import correctly added to enable testing of the range module.


283-432: Well-structured test cases with good coverage.

The test logic correctly validates:

  • Non-overlapping range insertion and ordering
  • Range lookup with find_range
  • Merge behavior for overlapping, adjacent, and contained ranges
  • Boundary cases at start and end of the range collection

Good use of defensive access patterns and diagnostic output in failure messages.


452-453: LGTM!

Correctly integrates test_range() into the test suite following the established pattern.

@Deterous
Copy link
Contributor

This PR adds support for --skip when dumping DVDs, thus fixing #69 ?
Could you also add support for DVD --lba-start and --lba-end in this PR? Could be implemented by adding [0, lba-start) and (lba-end, end] to protection ranges.

@superg
Copy link
Owner Author

superg commented Nov 28, 2025

This PR adds support for --skip when dumping DVDs, thus fixing #69 ? Could you also add support for DVD --lba-start and --lba-end in this PR? Could be implemented by adding [0, lba-start) and (lba-end, end] to protection ranges.

Will come in another PR, this one already has too much.

Please review my changes though, meanwhile I'm testing here by dumping my xbox discs.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
utils/endian.ixx (1)

77-84: Mirror unsigned-intermediate pattern and optionally constrain U to bytes.

The size static_assert is a solid guard here as well. For symmetry with endian_swap_from_array and to avoid implementation-defined behavior when T is signed (right-shifting negatives), consider shifting an unsigned copy of v:

 export template<typename T, typename U, std::size_t N>
 void endian_swap_to_array(U (&a)[N], T v)
 {
-    static_assert(sizeof(T) >= N * sizeof(U), "source type T must be large enough to contain all array data");
-
-    for(size_t i = 0; i < N; ++i)
-        a[i] = (U)(v >> CHAR_BIT * sizeof(U) * (N - 1 - i));
+    static_assert(sizeof(T) >= N * sizeof(U),
+                  "source type T must be large enough to contain all array data");
+
+    using UT = std::make_unsigned_t<T>;
+
+    UT uv = static_cast<UT>(v);
+
+    for (std::size_t i = 0; i < N; ++i)
+        a[i] = static_cast<U>(uv >> (CHAR_BIT * sizeof(U) * (N - 1 - i)));
 }

If the intent is strictly “array of raw bytes”, you might also add an optional constraint:

static_assert(std::is_unsigned_v<U>, "endian_swap_to_array expects unsigned element type U");

(This echoes an earlier review suggestion for this function.)

#!/bin/bash
# Optional: confirm that current uses of endian_swap_to_array pass unsigned U/T as expected.
rg -n "endian_swap_to_array" -C3
🧹 Nitpick comments (2)
range.ixx (1)

56-59: insert_range merge logic looks correct; consider documenting adjacency and a tiny micro‑opt

The new implementation correctly:

  • Rejects invalid ranges via throw_line instead of a boolean return.
  • Finds all existing ranges whose end >= range.start and start <= range.end (including touching ones) and merges them into a single [start, end) segment while preserving sorted order.

Because of the >= / <= checks, adjacent intervals like [a, b) and [b, c) will now be coalesced into [a, c). That’s a reasonable design, but it’s a behaviour change vs strictly non-overlapping, non‑coalescing semantics; worth calling out in a brief comment or doc so callers know that “touching” ranges are merged.

Minor nit: after ranges.erase(first_overlap, last_overlap); you know the insertion position is where first_overlap used to be. You could cache the index and use ranges.begin() + index instead of re‑running lower_bound to shave a tiny amount of work.

Also applies to: 63-79, 81-81

dvd/dvd_dump.ixx (1)

384-386: Kreon lock/unlock flow is clearer; RAII guard would make it exception‑safe

The Kreon handling is much improved:

  • You detect Kreon firmware and proactively switch to WXRIPPER before capacity/Xbox detection (Lines 384–393).
  • During the main loop, you delay locking until s >= xbox->lock_sector_start, then set kreon_locked = true and compute sector_shift while in the locked state (Lines 690–707).
  • At normal function exit you conditionally restore WXRIPPER if the drive was locked (Lines 843–849), and you also log an interrupt‑driven early stop (Line 835).

One remaining robustness gap is exception safety: any throw_line after the drive has been locked (e.g., from SCSI calls or structure validation) will bypass the final unlock block and potentially leave the drive in the locked state until the user intervenes.

Non‑blocking suggestion: consider wrapping the lock state in a small RAII helper that calls cmd_kreon_set_lock_state(*ctx.sptd, KREON_LockState::WXRIPPER) in its destructor when it knows the drive is currently locked. That would guarantee unlock on all exit paths (normal return and exceptions) without changing the high‑level control flow here.

Also applies to: 387-393, 690-708, 835-835, 843-849

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c36d79 and 8c96fad.

📒 Files selected for processing (5)
  • dvd/dvd_dump.ixx (11 hunks)
  • range.ixx (2 hunks)
  • tests/CMakeLists.txt (2 hunks)
  • tests/tests.cc (3 hunks)
  • utils/endian.ixx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/tests.cc
  • tests/CMakeLists.txt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-07T19:05:32.220Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/cmd.ixx:558-571
Timestamp: 2025-09-07T19:05:32.220Z
Learning: In the scsi/cmd.ixx file, there are multiple functions that use pointer-byte indexing for endianness conversion that could be prone to endianness issues. The maintainer prefers to address these systematically in a centralized manner rather than piecemeal fixes.

Applied to files:

  • utils/endian.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-windows (arm64, ARM64)
🔇 Additional comments (5)
utils/endian.ixx (2)

4-4: Include of <climits> is appropriate and necessary for CHAR_BIT.

This correctly satisfies the dependency introduced by the new templates using CHAR_BIT. No issues here.


30-38: Explicit specializations remain valid optimized fast paths.

The endian_swap specializations for uint16_t/32/64 still funnel to platform intrinsics while keeping the generic template in place. This looks fine and keeps the optimized paths centralized.

Also applies to: 41-49, 52-60

dvd/dvd_dump.ixx (3)

5-9: New headers and imports match the added functionality

The additions of <memory>, <optional>, and <vector>, plus the import dvd.xbox; and import range;, are consistent with the new use of std::shared_ptr, std::optional, std::vector, and the Xbox context/protection range utilities. No issues here.

Also applies to: 18-18, 21-21


380-383: Skip/protection ranges: semantics look coherent; confirm zero‑fill & success state are desired

The new protection handling around options.skip and Xbox security looks internally consistent:

  • protection is built from string_to_ranges<uint32_t>(options.skip) using insert_range, so user‑supplied and Xbox‑supplied ranges end up merged and sorted (Lines 380–383).
  • At the start of each loop iteration you limit sectors_to_read so that a batch never straddles a protection boundary (Lines 679–689), which keeps the “skip” and “read” paths cleanly separated.
  • In the main read path, if find_range(protection, s) hits, store is set true and no SCSI read is issued for that batch; drive_data stays as zero‑initialized memory (Lines 732–737).
  • When store is true in DUMP mode you:
    • Swap file_data with drive_data (so the ISO gets zero‑filled sectors),
    • Mark all file_state entries in the chunk as State::SUCCESS,
    • And later call rom_entry.update(...) as long as errors.scsi == 0 (Lines 772–772, 779–781, 829–831).
  • In REFINE/VERIFY, protected sectors also avoid SCSI reads; they are effectively treated as always‑good data.

This matches a “deliberately skipped / logically known content” interpretation: skipped or protected regions become zero‑filled, are not counted as SCSI errors, and participate in DAT/rom computation as long as the rest of the dump is error‑free.

If that’s the intended contract for --skip (i.e., intentional gaps that should not be distinguishable from error‑free sectors in the state file or DAT), then the implementation looks good. If instead you want skipped sectors to remain distinguishable (e.g., marked as ERROR_SKIP, excluded from rom_entry.update, or always re‑skipped in REFINE/VERIFY), you may want to adjust the state handling in these branches accordingly.

Also applies to: 676-676, 679-689, 732-737, 739-770, 772-772, 789-789, 829-831


482-482: Physical/manufacturer/CSS structure handling and logging look solid

A few notes on the structural metadata handling:

  • Manufacturer structures are now read per physical layer and written to *.manufacturer files using std::format for consistent file naming (Lines 482, 488, 492, 496–499); this aligns well with the existing *.physical naming and multi‑layer handling.
  • For non‑Blu‑ray DVDs, you reuse print_physical_structure after extracting the READ_DVD_STRUCTURE_LayerDescriptor from each physical structure buffer (Lines 561–564), which nicely centralizes the logging.
  • In REFINE mode, the disc’s current physical structures are compared byte‑for‑byte against the stored *.physical files, and a clear throw_line is raised on mismatch (Lines 603–607); that’s a good integrity check to ensure refinement is done on the same disc.
  • CSS/COPYRIGHT reading via cmd_read_disc_structure with strip_response_header and interpretation of READ_DVD_STRUCTURE_CopyrightInformation (Line 615 and subsequent code) is consistent with standard CSS authentication flows.

I don’t see correctness issues in these pieces; the behaviour and diagnostics look appropriate.

Also applies to: 488-488, 492-492, 496-501, 561-564, 606-607, 615-615

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
dvd/xbox.ixx (1)

209-210: Add explicit parentheses for clarity.

The conditional mixes && and || operators. While operator precedence makes this work, explicit grouping improves readability and prevents future maintenance errors.

-        if(xgd_version(layer0_last) == 1 && i >= 16 || xgd_version(layer0_last) != 1 && i != 0 && i != 3)
+        if((xgd_version(layer0_last) == 1 && i >= 16) || (xgd_version(layer0_last) != 1 && i != 0 && i != 3))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4869c8c and b390c48.

📒 Files selected for processing (2)
  • CMakeLists.txt (1 hunks)
  • dvd/xbox.ixx (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.
📚 Learning: 2025-10-21T21:23:42.149Z
Learnt from: superg
Repo: superg/redumper PR: 288
File: .github/workflows/cmake.yml:0-0
Timestamp: 2025-10-21T21:23:42.149Z
Learning: In the redumper project, REDUMPER_OS and REDUMPER_ARCH CMake variables are deprecated. Package naming now derives the suffix from the CMAKE_TOOLCHAIN_FILE basename (e.g., the toolchain file cmake/toolchains/macos-x64.cmake produces a package suffix of macos-x64).

Applied to files:

  • CMakeLists.txt
📚 Learning: 2025-10-21T21:22:45.817Z
Learnt from: superg
Repo: superg/redumper PR: 288
File: cmake/toolchains/macos-arm64.cmake:0-0
Timestamp: 2025-10-21T21:22:45.817Z
Learning: The redumper codebase uses only C++, not C, so CMAKE_C_COMPILER configuration is not needed in toolchain files.

Applied to files:

  • CMakeLists.txt
📚 Learning: 2025-11-28T01:02:39.514Z
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.

Applied to files:

  • dvd/xbox.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-windows (arm64, ARM64)
🔇 Additional comments (7)
CMakeLists.txt (1)

118-118: LGTM!

The module relocation from utils/xbox.ixx to dvd/xbox.ixx appropriately groups Xbox-related functionality with other DVD modules.

dvd/xbox.ixx (6)

1-20: LGTM!

Module declaration and imports are well-organized and appropriate for the Xbox security sector handling functionality.


26-31: LGTM!

The Context struct provides a clean interface for Xbox security context data.


288-291: Verify no integer underflow on l1_padding_length calculation.

If ss_lba_first <= layer0_last, the subtraction produces a negative value which wraps when stored in uint32_t. This would result in an extremely large padding value.

If this invariant is guaranteed by the XGD specification, consider adding an assertion or comment documenting the assumption:

// XGD spec guarantees ss_lba_first > layer0_last
assert(ss_lba_first > layer0_last && "Invalid layer addressing");
uint32_t l1_padding_length = ss_lba_first - layer0_last - 1;

165-198: LGTM!

The security layer descriptor reading and merging logic handles partial responses appropriately, with proper error handling for SCSI failures.


155-162: LGTM!

The PSN to LBA conversion logic correctly handles dual-layer disc addressing with the layer0_last adjustment.


139-145: LGTM!

Version mapping and lead-out sector constants are well-defined for the three XGD versions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
dvd/xbox.ixx (2)

34-136: Complex packed union structure for security layer data.

The SecurityLayerDescriptor union maps the on-disc security sector format with byte-level precision. The nested unions for xgd1/xgd2/xgd3 variants handle the different Xbox disc generations appropriately.

Note: The decimal offset comments on lines 98-100 appear incorrect (already flagged in a previous review).


220-244: Strict aliasing concern already flagged.

The uint16_t& casts on lines 232-233 and 240-241 were noted in a previous review for potential strict aliasing violations. The same bounds-check recommendation from the previous function applies here as well.

🧹 Nitpick comments (1)
dvd/xbox.ixx (1)

201-217: Add bounds check before casting security_sector to SecurityLayerDescriptor.

The function casts security_sector[0] to SecurityLayerDescriptor& without verifying that the vector has sufficient size. If an undersized vector is passed, this could lead to undefined behavior.

Consider adding a size check:

 export void get_security_layer_descriptor_ranges(std::vector<Range<uint32_t>> &protection, const std::vector<uint8_t> &security_sector)
 {
+    if(security_sector.size() < sizeof(SecurityLayerDescriptor))
+        throw_line("security sector too small");
+
     auto const &sld = (SecurityLayerDescriptor &)security_sector[0];
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b390c48 and 7ebb6cd.

📒 Files selected for processing (2)
  • dvd/dvd_dump.ixx (12 hunks)
  • dvd/xbox.ixx (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.
📚 Learning: 2025-11-28T01:02:39.514Z
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.

Applied to files:

  • dvd/dvd_dump.ixx
  • dvd/xbox.ixx
📚 Learning: 2025-09-07T19:05:32.220Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/cmd.ixx:558-571
Timestamp: 2025-09-07T19:05:32.220Z
Learning: In the scsi/cmd.ixx file, there are multiple functions that use pointer-byte indexing for endianness conversion that could be prone to endianness issues. The maintainer prefers to address these systematically in a centralized manner rather than piecemeal fixes.

Applied to files:

  • dvd/dvd_dump.ixx
  • dvd/xbox.ixx
📚 Learning: 2025-09-07T20:29:35.084Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/mmc.ixx:853-862
Timestamp: 2025-09-07T20:29:35.084Z
Learning: In scsi/mmc.ixx, the maintainer only adds pragma pack directives to structures when needed, not preemptively. They verify struct layouts work correctly through actual hardware testing rather than relying solely on static assertions.

Applied to files:

  • dvd/xbox.ixx
🔇 Additional comments (12)
dvd/xbox.ixx (4)

26-31: LGTM - Context struct is well-defined.

The Context struct provides a clean encapsulation for Xbox-specific state including the security sector data and key offsets needed for dump operations.


148-162: PSN to LBA conversion logic is correct.

The PSN_to_LBA function properly handles the standard DVD PSN offset (0x30000) and layer wrap-around for opposite track path discs.


165-184: LGTM - Security layer descriptor read with proper error handling.

The function correctly handles partial security sector reads for Kreon firmware, throws on initial failure, and returns a completeness indicator for caller logging.


258-314: Well-structured Xbox initialization with proper resource management.

The function correctly:

  • Returns nullptr for unrecognized XGD versions, allowing graceful fallback
  • Repairs XGD3 security sectors when custom Kreon firmware is available
  • Uses std::shared_ptr for proper ownership semantics
  • Efficiently transfers the security sector via swap()

The protection range insertion for L1 padding at line 307 correctly extends the skip regions beyond capacity for Xbox-specific layer handling.

dvd/dvd_dump.ixx (8)

380-382: LGTM - Protection ranges from skip option.

The code properly converts user-specified skip ranges using the templatized string_to_ranges and inserts them into the protection vector.


384-405: Proper early Kreon unlock and capacity validation.

Unlocking the Kreon drive early ensures READ_CAPACITY returns the correct value for Xbox disc detection. The block length validation guards against unsupported disc formats.


443-479: Robust Xbox/Kreon detection and security sector handling.

The detection logic correctly identifies Xbox discs when physical layer length differs from READ_CAPACITY. The security sector comparison during refine mode uses cleaned versions to avoid false mismatches from drive-specific variations.


643-657: Sector count determination logic is correct.

Based on learnings, this centralized sector count logic is intentionally designed to support multiple sources (READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size). For Xbox/Kreon XGD discs, sectors_count_xbox correctly takes priority since xbox::initialize() updates the layer descriptor with the true value from the security sector.


717-718: Verify sector_shift calculation cannot underflow.

The calculation xbox->layer1_video_start - xbox->lock_sector_start assigns the result of subtracting two uint32_t values to an int32_t. If layer1_video_start < lock_sector_start, this would underflow before the signed conversion.

Could you confirm that by design layer1_video_start >= lock_sector_start is always true for valid Xbox contexts? If not, consider adding a check or using signed arithmetic:

-            if(kreon_locked)
-                sector_shift = xbox->layer1_video_start - xbox->lock_sector_start;
+            if(kreon_locked)
+                sector_shift = static_cast<int32_t>(xbox->layer1_video_start) - static_cast<int32_t>(xbox->lock_sector_start);

743-781: Protection range skip logic correctly writes zero-filled sectors.

When a sector falls within a protection range, store=true is set without reading from the drive. The drive_data vector remains zero-initialized, which is the correct behavior for skip ranges (e.g., Xbox security sectors that cannot be read normally).


854-860: LGTM - Graceful Kreon drive re-unlock at operation end.

The non-throwing error handling for unlock failure is appropriate since the dump data is already complete. Logging the failure allows users to diagnose drive state issues.


840-842: Correct ROM entry update condition.

The ROM entry hash is only updated during dump mode when there are no SCSI errors, ensuring hash integrity for clean dumps only.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
dvd/xbox.ixx (2)

209-210: Add parentheses for clarity in complex conditional.

The operator precedence is technically correct (&& binds tighter than ||), but explicit parentheses would improve readability:

-        if(xgd_version(layer0_last) == 1 && i >= 16 || xgd_version(layer0_last) != 1 && i != 0 && i != 3)
+        if((xgd_version(layer0_last) == 1 && i >= 16) || (xgd_version(layer0_last) != 1 && i != 0 && i != 3))

201-217: Consider adding size validation before casting.

The cast on line 203 assumes security_sector has at least sizeof(SecurityLayerDescriptor) bytes. While callers likely ensure this, a defensive check would prevent undefined behavior if called with insufficient data.

 export void get_security_layer_descriptor_ranges(std::vector<Range<uint32_t>> &protection, const std::vector<uint8_t> &security_sector)
 {
+    if(security_sector.size() < sizeof(SecurityLayerDescriptor))
+        throw_line("security sector too small: {} < {}", security_sector.size(), sizeof(SecurityLayerDescriptor));
+
     auto const &sld = (SecurityLayerDescriptor &)security_sector[0];
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ebb6cd and b33ec81.

📒 Files selected for processing (2)
  • dvd/xbox.ixx (1 hunks)
  • range.ixx (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.
📚 Learning: 2025-11-28T01:02:39.514Z
Learnt from: superg
Repo: superg/redumper PR: 302
File: dvd/dvd_dump.ixx:395-405
Timestamp: 2025-11-28T01:02:39.514Z
Learning: In dvd/dvd_dump.ixx, the sector count determination logic (around lines 641-647) is intentionally centralized to support multiple sources: READ_CAPACITY, physical structures, and future options like ISO/UDF filesystem size. For Xbox/Kreon XGD discs, the physical structure sector count is correct to use because xbox::initialize() updates the layer0_ld.layer0_end_sector with the true value from the security sector before sectors_count_physical is calculated.

Applied to files:

  • dvd/xbox.ixx
📚 Learning: 2025-09-07T19:05:32.220Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/cmd.ixx:558-571
Timestamp: 2025-09-07T19:05:32.220Z
Learning: In the scsi/cmd.ixx file, there are multiple functions that use pointer-byte indexing for endianness conversion that could be prone to endianness issues. The maintainer prefers to address these systematically in a centralized manner rather than piecemeal fixes.

Applied to files:

  • dvd/xbox.ixx
📚 Learning: 2025-09-07T20:29:35.084Z
Learnt from: superg
Repo: superg/redumper PR: 283
File: scsi/mmc.ixx:853-862
Timestamp: 2025-09-07T20:29:35.084Z
Learning: In scsi/mmc.ixx, the maintainer only adds pragma pack directives to structures when needed, not preemptively. They verify struct layouts work correctly through actual hardware testing rather than relying solely on static assertions.

Applied to files:

  • dvd/xbox.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build-macos (arm64)
  • GitHub Check: build-macos (x64)
  • GitHub Check: build-windows (x86, Win32)
  • GitHub Check: build-windows (arm64, ARM64)
  • GitHub Check: build-windows (x64, x64)
  • GitHub Check: build-linux (x64, ubuntu-24.04)
  • GitHub Check: build-linux (x86, ubuntu-24.04)
  • GitHub Check: build-linux (arm64, ubuntu-24.04-arm)
🔇 Additional comments (5)
range.ixx (1)

55-84: LGTM!

The overlap detection and merging logic is correct. The use of >= and <= in overlap detection (lines 65, 69) means adjacent ranges are also merged, which is appropriate behavior for protection/skip ranges. The iterator invalidation after erase is handled correctly by recalculating from insertion_index.

dvd/xbox.ixx (4)

34-136: Packed union structure looks correct for binary parsing.

The struct layout with #pragma pack(push, 1) is appropriate for interpreting raw security sector data. The hex offset comments align with field names.


230-244: Good use of memcpy for safe unaligned writes.

The memcpy approach correctly avoids the strict aliasing and alignment issues that were flagged in a previous review. This is the portable way to write to potentially unaligned offsets within packed structures.


296-314: Verify assumptions about sector ordering for signed arithmetic.

The calculations on lines 300 and 313 perform signed subtraction before assigning to unsigned:

  • l1_padding_length = ss_lba_first - layer0_last - 1
  • layer1_video_start = layer0_last + 1 - lba_first

For valid XGD data these should always be positive, but if the security sector contains unexpected values (corrupted data, non-Xbox disc misidentified), the signed-to-unsigned conversion could silently produce incorrect large values.

Consider whether defensive checks are warranted:

int32_t l1_padding = ss_lba_first - layer0_last - 1;
if(l1_padding < 0)
    throw_line("invalid security sector: unexpected layer ordering");
uint32_t l1_padding_length = static_cast<uint32_t>(l1_padding);

165-184: LGTM!

The error handling strategy is reasonable: fail hard on initial read failure, but tolerate partial reads for subsequent sectors. The return value correctly indicates whether a complete security sector was obtained.

@superg superg merged commit 157cf1b into main Dec 3, 2025
11 checks passed
@superg superg deleted the dvd_iso_volume_size branch December 12, 2025 01:15
@coderabbitai coderabbitai bot mentioned this pull request Dec 24, 2025
@coderabbitai coderabbitai bot mentioned this pull request Jan 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants