Skip to content

Extract Content IDs from PS4/PS5 PKGs#390

Open
RobbedColek wants to merge 3 commits into
superg:mainfrom
RobbedColek:main
Open

Extract Content IDs from PS4/PS5 PKGs#390
RobbedColek wants to merge 3 commits into
superg:mainfrom
RobbedColek:main

Conversation

@RobbedColek

@RobbedColek RobbedColek commented Jun 10, 2026

Copy link
Copy Markdown

Reads the Content ID from the PKG headers found on the disc for PS4/PS5 system in app directory that match provided filename and prints them as part of redump info.

image

Summary by CodeRabbit

  • New Features
    • PS4 system information now extracts and displays package content IDs from supported ISO package files when available.
    • PS5 system information now also collects and displays package content IDs (e.g., from app_sc.pkg) during its info output.
  • Refactor
    • Shared content ID lookup logic was consolidated to keep PS4 and PS5 behavior consistent, with no output shown when no content IDs are found.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a PS4 helper to extract package content IDs from ISO9660 app entries and prints them in PS4::printInfo; PS5 now inherits from SystemPS4 and uses the helper to extract and print app_sc.pkg content IDs.

Changes

PS4 Content ID Extraction and PS5 Inheritance

Layer / File(s) Summary
PS4 constants and getContentIds implementation
systems/ps4.ixx
Defines constants for pkg header size, magic value, magic/content-ID offsets, and filename variants. Implements SystemPS4::getContentIds to scan app/* subdirectories, attempt multiple package filenames, validate a 4-byte magic at offset 0x00, extract a 36-byte content ID from offset 0x40, and return comma-separated concatenated IDs.
PS4 printInfo content ID output
systems/ps4.ixx
SystemPS4::printInfo calls getContentIds(root_directory, _PKG_FILE_NAMES), prints content ID(s): ... when non-empty, and returns early when no IDs are found.
PS5 inheritance switch and printInfo integration
systems/ps5.ixx
systems.ps5 imports systems.ps4; SystemPS5 class inherits from SystemPS4 instead of System. SystemPS5::printInfo calls inherited getContentIds for app_sc.pkg, returns early if result is empty, and prints content ID(s): ... line when IDs are present.

Sequence Diagram

sequenceDiagram
  participant SystemPS4
  participant getContentIds
  participant ISO9660Root as app directory
  participant SystemPS5

  SystemPS4->>getContentIds: getContentIds(root_directory, pkg_filenames)
  getContentIds->>ISO9660Root: enumerate subdirectories
  ISO9660Root-->>getContentIds: pkg entries
  getContentIds->>getContentIds: validate magic and extract content IDs
  getContentIds-->>SystemPS4: concatenated IDs or empty
  
  SystemPS5->>getContentIds: getContentIds(root_directory, app_sc.pkg) [inherited]
  getContentIds->>ISO9660Root: enumerate subdirectories
  getContentIds-->>SystemPS5: concatenated IDs or empty
  SystemPS5->>SystemPS5: print IDs or return early
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Through ISO fields I hopped to find,
Magic bytes of a careful kind,
Thirty-six secrets locked away,
PS4 reads them every day,
PS5 inherits—what cheer, what joy!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Extract Content IDs from PS4/PS5 PKGs' directly and clearly describes the main change: adding functionality to extract Content IDs from PS4/PS5 package files, which is confirmed by the detailed summary showing new getContentIds helper methods and content ID extraction logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@systems/ps4.ixx`:
- Around line 85-105: The code reads fixed offsets from app_pkg_raw (via
app_pkg_entry->read()) without size checks, risking out-of-bounds access when
the buffer is truncated; update the logic that computes app_pkg_magic and
constructs app_pkg_content_id (using pkg_magic_offset, pkg_magic_size,
pkg_content_id_offset, pkg_content_id_size, and app_pkg_content_id) to first
verify app_pkg_raw.size() is at least the maximum required offset+size (e.g.
max(pkg_magic_offset+pkg_magic_size, pkg_content_id_offset+pkg_content_id_size))
and if not, silently skip this entry (no warning) so truncated/corrupt PKGs are
ignored safely. Ensure subsequent uses of app_pkg_raw assume the validated size.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4cad8068-5283-4805-97c9-5446d4855bb9

📥 Commits

Reviewing files that changed from the base of the PR and between d8baf3d and b13f6e1.

📒 Files selected for processing (2)
  • systems/ps4.ixx
  • systems/ps5.ixx

Comment thread systems/ps4.ixx Outdated
- added size validation,
- removed unused const,
- set some of params/variables to const,
- adapted code style to match project.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@systems/ps4.ixx`:
- Around line 87-90: The current implementation in the app_pkg_entry->read()
call loads the entire PKG file contents, but the subsequent logic only needs the
header bytes up to _PKG_HEADER_SIZE. Replace the full-file read with a bounded
read operation that retrieves only the header bytes (0x1000 bytes as defined by
_PKG_HEADER_SIZE) to reduce latency and memory consumption for large PKG files.
Ensure the bounded read still provides enough data for the size validation check
and any subsequent magic/content-ID checks that depend on the header.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3c22fa38-cb8f-4e89-8f44-67f60fee3f39

📥 Commits

Reviewing files that changed from the base of the PR and between 4593348 and 3c8b10f.

📒 Files selected for processing (2)
  • systems/ps4.ixx
  • systems/ps5.ixx
🚧 Files skipped from review as they are similar to previous changes (1)
  • systems/ps5.ixx

Comment thread systems/ps4.ixx
Comment on lines +87 to +90
auto app_pkg_raw = app_pkg_entry->read();

if(app_pkg_raw.size() < _PKG_HEADER_SIZE)
continue;

@coderabbitai coderabbitai Bot Jun 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid full-file reads for PKG header parsing.

At Line 87, app_pkg_entry->read() loads the entire PKG even though this logic only needs header bytes up to _PKG_HEADER_SIZE (0x1000). For large PS4/PS5 PKGs, this can significantly increase redumper info latency and memory pressure. Prefer a bounded header read (or a header-only helper) before magic/content-ID checks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@systems/ps4.ixx` around lines 87 - 90, The current implementation in the
app_pkg_entry->read() call loads the entire PKG file contents, but the
subsequent logic only needs the header bytes up to _PKG_HEADER_SIZE. Replace the
full-file read with a bounded read operation that retrieves only the header
bytes (0x1000 bytes as defined by _PKG_HEADER_SIZE) to reduce latency and memory
consumption for large PKG files. Ensure the bounded read still provides enough
data for the size validation check and any subsequent magic/content-ID checks
that depend on the header.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I thought the read() opens the pointer to the data that then can be read on demand? Unsure if I am in the wrong or AI.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find iso9660 filesystem module files
fd -e ixx -e hh -e h -e cc -e cpp iso9660

# Search for the read() method implementation in iso9660
rg -n "read" --type-add 'ixx:*.ixx' --type ixx -C3

Length of output: 203090



@RobbedColek — good instinct to question it, but having looked at the actual implementation in filesystem/iso9660/iso9660_entry.ixx, read() is an eager, full-file load, not a lazy reader:

std::vector<uint8_t> read(bool form2 = false, bool *form_hint = nullptr)
{
    // allocates a buffer for the ENTIRE file upfront
    std::vector<uint8_t> sectors(sectorsSize() * _dataReader->sectorSize(form2));

    // reads ALL sectors into the buffer immediately
    uint32_t sectors_read = _dataReader->read(sectors.data(), sectorsLBA(), sectorsSize(), form2, form_hint);

    sectors.resize(size);
    return sectors; // returns the full contents
}

It pre-allocates sectorsSize() × sectorSize bytes (the whole file), calls through to _dataReader->read() (which hits the underlying file stream), and returns a fully populated std::vector<uint8_t>. There is no lazy/streaming interface here.

So the concern is valid: for a PS4/PS5 app PKG that can easily be several gigabytes, app_pkg_entry->read() will attempt to load the entire file into RAM just to check the first 0x40 + 36 = 76 bytes. A bounded read (if the underlying reader supports seeking + partial reads) or a dedicated header-reading helper would be significantly more efficient.


🧠 Learnings used
Learnt from: Didrole
Repo: superg/redumper PR: 356
File: systems/gc.ixx:53-59
Timestamp: 2026-02-26T22:08:07.395Z
Learning: In systems/gc.ixx and systems/wii.ixx (and other files under systems with .ixx extension), when BCA file validation fails (e.g., unexpected size), the function should return silently and not emit a warning. Reviewers should verify that BCA validation failures do not log warnings and consider adding tests to cover the silent failure behavior.

Learnt from: Didrole
Repo: superg/redumper PR: 356
File: systems/wii.ixx:54-60
Timestamp: 2026-02-26T22:08:15.577Z
Learning: In systems/wii.ixx and systems/gc.ixx, when a .bca file exists but its size does not match _WII_BCA_STRUCTURE_SIZE or _GC_BCA_STRUCTURE_SIZE, the code is expected to skip silently without emitting a warning or error. This behavior should be consistently maintained across similar modules. If this pattern could appear in other modules, prefer the glob pattern systems/**/*.ixx to cover all related files. Consider adding a brief inline comment near the relevant size-check to document the rationale, and add a targeted unit/integration test to verify there is no warning or error emitted for mismatched sizes.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@RobbedColek looks like this is legit callout, those pkg files are huge.
It's a little bit inconvenient but I would ask instead of using directory read(), use data_reader directly and directory entry sectorsLBA() method to get LBA and only read what you need.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread systems/ps4.ixx
Comment on lines +87 to +90
auto app_pkg_raw = app_pkg_entry->read();

if(app_pkg_raw.size() < _PKG_HEADER_SIZE)
continue;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@RobbedColek looks like this is legit callout, those pkg files are huge.
It's a little bit inconvenient but I would ask instead of using directory read(), use data_reader directly and directory entry sectorsLBA() method to get LBA and only read what you need.

Comment thread systems/ps4.ixx
Comment on lines +92 to +96
uint32_t app_pkg_magic =
(static_cast<uint32_t>(app_pkg_raw[_PKG_MAGIC_OFFSET + 0]) << 24) |
(static_cast<uint32_t>(app_pkg_raw[_PKG_MAGIC_OFFSET + 1]) << 16) |
(static_cast<uint32_t>(app_pkg_raw[_PKG_MAGIC_OFFSET + 2]) << 8) |
(static_cast<uint32_t>(app_pkg_raw[_PKG_MAGIC_OFFSET + 3]) << 0);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Comment thread systems/ps4.ixx
Comment on lines +118 to +122
static constexpr uint32_t _PKG_HEADER_SIZE = 0x1000;
static constexpr uint32_t _PKG_MAGIC = 0x7F434E54;
static constexpr uint32_t _PKG_MAGIC_OFFSET = 0x00;
static constexpr uint32_t _PKG_CONTENT_ID_OFFSET = 0x40;
static constexpr uint32_t _PKG_CONTENT_ID_SIZE = 36;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'd ask you to define a FileHeader structure, like here: https://www.psdevwiki.com/ps4/PKG_files and just use file_header.pkg_content_id in the above code.

In general I prefer the code to be clear to understand for somebody who wants to learn what is read and why is read.

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.

2 participants