📄 dvdsubber_kernel.cpp
字号:
} else if (hard_lba >= disc_info->vmg_ifo_sector) {
PatchVMGIFO(hard_lba - disc_info->vmg_ifo_sector, buffer);
} else {
if (check_udf_descriptor(buffer, 261) >= 0) {
// file entry
unsigned start_lba = GetICBStartLBA(buffer, hard_lba);
if (start_lba) {
if (start_lba < disc_info->titlesets[title].vts_vobs_sector) {
// no action
} else if (start_lba < disc_info->titlesets[title].vts_bup_sector) {
// need to juggle the sizes: try to figure out which VTS_##_# file this is
unsigned last_digit_minus_1 = (start_lba - disc_info->titlesets[title].vts_vobs_sector) / 0x7F000; // round down
if (last_digit_minus_1 > 8)
last_digit_minus_1 = 8; // does this make sense?
unsigned new_start_lba = disc_info->titlesets[title].vts_vobs_sector + last_digit_minus_1 * 0x7FFFF;
unsigned length = 0x7FFFF;
unsigned soft_end = Hard2Soft(disc_info->titlesets[title].vts_bup_sector);
if (new_start_lba > soft_end) new_start_lba = soft_end;
if (new_start_lba + length > soft_end) length = soft_end - new_start_lba;
SetICBLengthInBlocks(buffer, length);
SetICBStartLBA(buffer, hard_lba, new_start_lba);
} else {
start_lba += Hard2Soft(disc_info->titlesets[title].vts_bup_sector) - disc_info->titlesets[title].vts_bup_sector;
SetICBStartLBA(buffer, hard_lba, start_lba);
}
RecalcCRC(buffer);
}
} else if (check_udf_descriptor(buffer, 5) >= 0) {
// partition descriptor
Put4(buffer+192, Hard2Soft(Get4(buffer+192)));
RecalcCRC(buffer);
}
}
}
void DVDSubberKernel::TranslateRelativeSector(unsigned char* pos, unsigned hard_sector, bool and_size) {
unsigned rel = Get4(pos);
unsigned offset = rel & 0x7FFFFFFF;
if (offset >= 0x3FFFFFFF)
return;
unsigned backward = rel & 0x80000000;
unsigned hard_sector_2 = backward ? hard_sector-offset : hard_sector + offset;
unsigned soft_sector_2 = Hard2Soft(hard_sector_2);
int soft_rel = soft_sector_2 - Hard2Soft(hard_sector);
Put4(pos, soft_rel >= 0 ? soft_rel : (0x80000000 - soft_rel));
if (and_size) {
unsigned size = pos[4]*256 + pos[5];
if (size != 0 && size != 0xFFFF) {
unsigned soft_size = Hard2Soft(hard_sector_2 + size) - soft_sector_2;
pos[4] = soft_size >> 8;
pos[5] = soft_size;
}
}
}
void DVDSubberKernel::UpdateSectorTable(unsigned offset, unsigned end_offset, unsigned record_min, unsigned record_size, unsigned base_lba, unsigned ifo_sector, unsigned char* buffer) {
record_min *= 4;
record_size *= 4;
int buf_offset;
unsigned record_pos;
if (offset < ifo_sector*2048) {
buf_offset = 0;
record_pos = (ifo_sector*2048 - offset) % record_size;
} else {
buf_offset = (offset - ifo_sector*2048);
record_pos = 0;
}
int buf_end_offset = end_offset - ifo_sector*2048;
if (buf_end_offset > 2048) {
buf_end_offset = 2048;
}
for (int i = buf_offset; i < buf_end_offset; i += 4) {
if (record_pos >= record_min) {
TranslateRelativeSector(&buffer[i], base_lba, false);
}
record_pos += 4;
if (record_pos >= record_size)
record_pos -= record_size;
}
}
void DVDSubberKernel::PatchVMGIFO(unsigned ifo_sector, unsigned char* buffer) {
UpdateSectorTable(disc_info->vmg_tt_srpt_offset, disc_info->vmg_tt_srpt_end_offset, 2, 3, disc_info->vmg_ifo_sector, ifo_sector, buffer);
// FIXME: VMG copy of subpicture info
}
void DVDSubberKernel::PatchVTSIFO(unsigned ts, const TitleSetInfo& tsi, unsigned ifo_sector, unsigned char* buffer) {
if (ts != title) return;
if (ifo_sector == 0) {
TranslateRelativeSector(&buffer[4], tsi.vts_ifo_sector, false);
// FIXME: hack
unsigned tracks = tsi.number_of_existing_subpicture_tracks;
buffer[0x255] = tracks + 1;
g_callbacks->MemSet(buffer + 0x256 + tracks*6, 0, 6);
// buffer[0x256+tracks*6] = 1;
// buffer[0x256+tracks*6+2] = 'j';
// buffer[0x256+tracks*6+3] = 'a';
} else {
for (unsigned pgc = 0; pgc < tsi.num_pgcs; ++pgc) {
UpdateSectorTable(
tsi.pgcs[pgc].cell_playback_info_table_offset,
tsi.pgcs[pgc].cell_playback_info_table_end_offset,
2, 6,
tsi.vts_vobs_sector,
ifo_sector, buffer);
int ss_offset = (tsi.pgcs[pgc].subpicture_status_offset + 4 * tsi.number_of_existing_subpicture_tracks) - (ifo_sector * 2048);
if (ss_offset >= 0 && ss_offset <= 2044) {
Put4(&buffer[ss_offset], 0x80000000 + 0x01010101 * tsi.number_of_existing_subpicture_tracks);
}
for (int pal = 0; pal < palette_size; ++pal) {
int pal_offset = tsi.pgcs[pgc].subpicture_status_offset - ifo_sector * 2048 + 0x88 + 4*15 - 4*pal;
if (pal_offset >= 0 && pal_offset <= 2044) {
Put4(&buffer[pal_offset], palette[pal]);
}
}
}
for (unsigned tmap = 0; tmap < tsi.num_tmaps; ++tmap) {
UpdateSectorTable(
tsi.tmaps[tmap].offset, tsi.tmaps[tmap].end_offset,
0, 1, tsi.vts_vobs_sector,
ifo_sector, buffer);
}
UpdateSectorTable(tsi.vts_c_adt_offset, tsi.vts_c_adt_end_offset, 1, 3, tsi.vts_vobs_sector, ifo_sector, buffer);
UpdateSectorTable(tsi.vts_vobu_admap_offset, tsi.vts_vobu_admap_end_offset, 0, 1, tsi.vts_vobs_sector, ifo_sector, buffer);
}
}
// returns true if hard sector range, false if subtitle
bool DVDSubberKernel::FindLBASource(unsigned soft_lba, unsigned num_blocks, unsigned* run_length, unsigned* hard_lba, SubpictureInfo** psi, unsigned* subpicture_rba) {
unsigned earlier_soft_sectors = 0;
SubpictureInfo* si = subpic_inf;
for (int subpic = 0; subpic < num_subpics; ++subpic, si = si->next) {
unsigned subpic_start = si->hard_lba + earlier_soft_sectors;
if (subpic_start > soft_lba) {
*run_length = Min(subpic_start-soft_lba, num_blocks);
*hard_lba = soft_lba - earlier_soft_sectors;
return true;
}
unsigned subpic_end = subpic_start + si->num_sectors;
if (subpic_end > soft_lba) {
*run_length = Min(subpic_end-soft_lba, num_blocks);
*psi = si;
*subpicture_rba = soft_lba - subpic_start;
return false;
}
earlier_soft_sectors += si->num_sectors;
}
*run_length = num_blocks;
*hard_lba = soft_lba - earlier_soft_sectors;
return true;
}
scsi_result_t DVDSubberKernel::ReadHardSectors(unsigned lba, unsigned count, unsigned char* buffer, SenseData* sense) {
static unsigned char cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Put4(&cdb[5], count); // order matters here...
Put4(&cdb[2], lba);
unsigned long buflen = count * 2048;
return child->ScsiCommand(child, cdb, 10, buffer, &buflen, 1, sense);
}
scsi_result_t DVDSubberKernel::ReadSectors(unsigned soft_lba, unsigned num_soft_sectors, unsigned char* buffer, SenseData* sense) {
//printf("\nrange: %06X - %06X\n", soft_lba, soft_lba + num_soft_sectors);
// first find the range of hard sectors to read
unsigned pos = 0;
unsigned first_hard_sector = 0, num_hard_sectors = 0;
while (pos < num_soft_sectors) {
unsigned run_length, hard_lba, subpic_rba;
SubpictureInfo* si;
if (FindLBASource(soft_lba + pos, num_soft_sectors - pos, &run_length, &hard_lba, &si, &subpic_rba)) {
// hard
if (num_hard_sectors == 0) {
first_hard_sector = hard_lba;
}
num_hard_sectors += run_length;
}
pos += run_length;
}
//printf(" hard: %06X - %06X\n", first_hard_sector, first_hard_sector + num_hard_sectors);
// now read them
unsigned char* hardp = buffer + (num_soft_sectors - num_hard_sectors) * 2048;
scsi_result_t result = ReadHardSectors(first_hard_sector, num_hard_sectors, hardp, sense);
if (result != SCSIRESULT_SUCCESS) return result;
// now go back and put everything into place
pos = 0;
unsigned char* p = buffer;
while (pos < num_soft_sectors) {
unsigned run_length, hard_lba, subpic_rba;
SubpictureInfo* si;
bool hard = FindLBASource(soft_lba + pos, num_soft_sectors - pos, &run_length, &hard_lba, &si, &subpic_rba);
for (unsigned i=0; i<run_length; ++i) {
if (hard) {
if (p != hardp) {
g_callbacks->MemCpy(p, hardp, 2048);
}
PatchHardSector(hard_lba, p);
hardp += 2048;
++hard_lba;
} else {
GenerateSubpictureSector(si, subpic_rba, p);
++subpic_rba;
}
p += 2048;
}
pos += run_length;
}
return SCSIRESULT_SUCCESS;
}
scsi_result_t ScsiCommand(DvsDeviceKernel* _self, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
DVDSubberKernel* self = (DVDSubberKernel*)_self;
if (self->state == stateActive || cdb[0] == 0x12) {
unsigned char newcdb[16];
if (self->num_subpics > 0) {
switch (cdb[0]) {
case SCSIOP_READ:
{
unsigned first_sector = Get4(&cdb[2]);
unsigned num_sectors = cdb[7]*256+cdb[8];
return self->ReadSectors(first_sector, num_sectors, buffer, sense);
}
case SCSIOP_READ_CAPACITY:
{
scsi_result_t result = self->child->ScsiCommand(self->child, cdb, cdblen, buffer, pbuflen, inout, sense);
if (result == SCSIRESULT_SUCCESS && *pbuflen >= 4) {
Put4(buffer, self->Hard2Soft(Get4(buffer)));
}
return result;
}
case SCSIOP_REPORT_KEY:
g_callbacks->MemCpy(newcdb, cdb, cdblen);
Put4(newcdb+2, self->Soft2Hard(Get4(newcdb+2)));
cdb = newcdb;
break;
}
}
return self->child->ScsiCommand(self->child, cdb, cdblen, buffer, pbuflen, inout, sense);
} else if (self->state == stateUpdating) {
return MAKE_SCSIRESULT_ERROR(0x23A00); // MEDIUM NOT PRESENT
} else /*if (self->state == stateUpdated)*/ {
self->state = stateActive;
return MAKE_SCSIRESULT_ERROR(0x62800); // NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED
}
}
extern "C"
dvs_scsi_func* __cdecl GetDispatchFunc() { return ScsiCommand; }
extern "C"
void* __cdecl SetState(DVDSubberKernel* self, int state) { self->state = state; return 0; }
extern "C"
void __cdecl DvdsynthDriverInit(DvsDockingBayKernelGlobal* callbacks) {
g_callbacks = callbacks;
}
extern "C"
unsigned __stdcall DLLEntry(void*, unsigned, void*) { return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -