Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate extra xbox files #198

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 10 additions & 27 deletions dvd/dvd_dump.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -507,39 +507,15 @@ export bool redumper_dump_dvd(Context &ctx, const Options &options, DumpMode dum
auto &ss_layer_descriptor = (READ_DVD_STRUCTURE_LayerDescriptor &)security_sector[0];

int32_t ss_lba_first = sign_extend<24>(endian_swap(ss_layer_descriptor.data_start_sector));
int32_t ss_layer0_last = sign_extend<24>(endian_swap(ss_layer_descriptor.layer0_end_sector));

uint32_t l1_padding_length = ss_lba_first - layer0_last - 1;
if(xgd_type == XGD_Type::XGD3)
l1_padding_length += 4096;

// extract security sector ranges
bool is_xgd1 = (xgd_type == XGD_Type::XGD1);
// extract security sector ranges from security sector
xbox_skip_ranges = get_security_sector_ranges(ss_layer_descriptor);

const auto media_specific_offset = offsetof(READ_DVD_STRUCTURE_LayerDescriptor, media_specific);
uint8_t num_ss_regions = ss_layer_descriptor.media_specific[1632 - media_specific_offset];
// partial pre-compute of conversion to Layer 1
const uint32_t layer1_offset = (ss_layer0_last * 2) - 0x30000 + 1;

for(int ss_pos = 1633 - media_specific_offset, i = 0; i < num_ss_regions; ss_pos += 9, ++i)
{
uint32_t start_psn = ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 3] << 16) | ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 4] << 8)
| (uint32_t)ss_layer_descriptor.media_specific[ss_pos + 5];
uint32_t end_psn = ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 6] << 16) | ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 7] << 8)
| (uint32_t)ss_layer_descriptor.media_specific[ss_pos + 8];
if((i < 8 && is_xgd1) || (i == 0 && !is_xgd1))
{
// Layer 0
xbox_skip_ranges.push_back({ start_psn - 0x30000, end_psn - 0x30000 });
}
else if((i < 16 && is_xgd1) || (i == 3 && !is_xgd1))
{
// Layer 1
xbox_skip_ranges.push_back({ layer1_offset - (start_psn ^ 0xFFFFFF), layer1_offset - (end_psn ^ 0xFFFFFF) });
}
}

// append L1 padding to ranges
// append L1 padding to skip ranges
xbox_skip_ranges.push_back({ sectors_count, sectors_count + l1_padding_length - 1 });

// sort the skip ranges
Expand Down Expand Up @@ -952,6 +928,13 @@ export bool redumper_dump_dvd(Context &ctx, const Options &options, DumpMode dum
status = cmd_kreon_set_lock_state(*ctx.sptd, KREON_LockState::WXRIPPER);
if(status.status_code)
LOG("warning: failed to unlock drive at end of dump, SCSI ({})", SPTD::StatusMessage(status));

// generate .dmi, .pfi, .ss if requested
if(options.generate_extra_xbox)
{
auto image_prefix = (std::filesystem::path(options.image_path) / options.image_name).string();
generate_extra_xbox(image_prefix);
}
}

if(!signal.interrupt())
Expand Down
8 changes: 8 additions & 0 deletions hash.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export void redumper_hash(Context &ctx, Options &options)
else if(std::filesystem::exists(image_prefix + ".iso"))
{
files.push_back(image_prefix + ".iso");

// hash xbox extras
if(std::filesystem::exists(image_prefix + ".dmi"))
files.push_back(image_prefix + ".dmi");
if(std::filesystem::exists(image_prefix + ".pfi"))
files.push_back(image_prefix + ".pfi");
if(std::filesystem::exists(image_prefix + ".ss"))
files.push_back(image_prefix + ".ss");
}
else
throw_line("image file not found");
Expand Down
5 changes: 5 additions & 0 deletions options.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export struct Options
bool overread_leadout;
bool force_unscrambled;
bool force_refine;
bool generate_extra_xbox;


Options(int argc, const char *argv[])
Expand Down Expand Up @@ -94,6 +95,7 @@ export struct Options
, overread_leadout(false)
, force_unscrambled(false)
, force_refine(false)
, generate_extra_xbox(false)
{
for(int i = 1; i < argc; ++i)
arguments += str_quoted_if_space(argv[i]) + " ";
Expand Down Expand Up @@ -240,6 +242,8 @@ export struct Options
force_unscrambled = true;
else if(key == "--force-refine")
force_refine = true;
else if(key == "--generate-extra-xbox")
generate_extra_xbox = true;
// unknown option
else
{
Expand Down Expand Up @@ -334,6 +338,7 @@ export struct Options
LOG("\t--legacy-subs \treplicate DIC style subchannel based track split");
LOG("\t--skip-fill=VALUE \tfill byte value for skipped sectors (default: 0x{:02X})", skip_fill);
LOG("\t--iso9660-trim \ttrim each ISO9660 data track to PVD volume size, useful for discs with fake TOC");
LOG("\t--generate-extra-xbox \tgenerate extra xbox files (.dmi/.pfi/.ss from .manufacturer/.physical/.security)");
LOG("");
LOG("\t(miscellaneous)");
LOG("\t--lba-start=VALUE \tLBA to start dumping from");
Expand Down
94 changes: 94 additions & 0 deletions utils/xbox.ixx
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
module;
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#include "throw_line.hh"

export module utils.xbox;

import dump;
import options;
import scsi.cmd;
import scsi.mmc;
import scsi.sptd;
import utils.endian;
import utils.file_io;
import utils.logger;
import utils.misc;



Expand Down Expand Up @@ -112,6 +121,38 @@ export XGD_Type get_xgd_type(const READ_DVD_STRUCTURE_LayerDescriptor &ss_layer_
}
}

export std::vector<std::pair<uint32_t, uint32_t>> get_security_sector_ranges(const READ_DVD_STRUCTURE_LayerDescriptor &ss_layer_descriptor)
{
std::vector<std::pair<uint32_t, uint32_t>> ss_ranges;

const auto media_specific_offset = offsetof(READ_DVD_STRUCTURE_LayerDescriptor, media_specific);
uint8_t num_ss_regions = ss_layer_descriptor.media_specific[1632 - media_specific_offset];
bool is_xgd1 = (get_xgd_type(ss_layer_descriptor) == XGD_Type::XGD1);
// partial pre-compute of conversion to Layer 1
int32_t ss_layer0_last = sign_extend<24>(endian_swap(ss_layer_descriptor.layer0_end_sector));
const uint32_t layer1_offset = (ss_layer0_last * 2) - 0x30000 + 1;

for(int ss_pos = 1633 - media_specific_offset, i = 0; i < num_ss_regions; ss_pos += 9, ++i)
{
uint32_t start_psn = ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 3] << 16) | ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 4] << 8)
| (uint32_t)ss_layer_descriptor.media_specific[ss_pos + 5];
uint32_t end_psn = ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 6] << 16) | ((uint32_t)ss_layer_descriptor.media_specific[ss_pos + 7] << 8)
| (uint32_t)ss_layer_descriptor.media_specific[ss_pos + 8];
if((i < 8 && is_xgd1) || (i == 0 && !is_xgd1))
{
// Layer 0
ss_ranges.push_back({ start_psn - 0x30000, end_psn - 0x30000 });
}
else if((i < 16 && is_xgd1) || (i == 3 && !is_xgd1))
{
// Layer 1
ss_ranges.push_back({ layer1_offset - (start_psn ^ 0xFFFFFF), layer1_offset - (end_psn ^ 0xFFFFFF) });
}
}

return ss_ranges;
}

export void clean_xbox_security_sector(std::vector<uint8_t> &security_sector)
{
XGD_Type xgd_type = get_xgd_type((READ_DVD_STRUCTURE_LayerDescriptor &)security_sector[0]);
Expand Down Expand Up @@ -215,4 +256,57 @@ export bool xbox_get_security_sector(SPTD &sptd, std::vector<uint8_t> &response_
return true;
}

export void generate_extra_xbox(std::string &image_prefix)
{
std::filesystem::path manufacturer_path(image_prefix + ".manufacturer");
std::filesystem::path physical_path(image_prefix + ".physical");
std::filesystem::path security_path(image_prefix + ".security");

if(std::filesystem::exists(security_path))
{
std::filesystem::path dmi_path(image_prefix + ".dmi");
std::filesystem::path pfi_path(image_prefix + ".pfi");
std::filesystem::path ss_path(image_prefix + ".ss");

// trim the 4 byte header from .manufacturer and write it to a .dmi
auto manufacturer = read_vector(manufacturer_path);
if(!manufacturer.empty() && manufacturer.size() == 2052)
{
manufacturer.erase(manufacturer.begin(), manufacturer.begin() + 4);
write_vector(dmi_path, manufacturer);
}
else
{
LOG("warning: could not generate DMI, unexpected file size ({})", manufacturer_path.filename().string());
}

// trim the 4 byte header from .physical and write it to a .pfi
auto physical = read_vector(physical_path);
if(!physical.empty() && physical.size() == 2052)
{
physical.erase(physical.begin(), physical.begin() + 4);
write_vector(pfi_path, physical);
}
else
{
LOG("warning: could not generate PFI, unexpected file size ({})", physical_path.filename().string());
}

// clean the .security and write to a .ss
auto security = read_vector(security_path);
if(!security.empty() && security.size() == 2048)
{
clean_xbox_security_sector(security);
write_vector(ss_path, security);

LOG("security sector ranges:");
auto security_ranges = get_security_sector_ranges((READ_DVD_STRUCTURE_LayerDescriptor &)security[0]);
for(const auto &range : security_ranges)
{
LOG(" {}-{}", range.first, range.second);
}
}
}
}

}