gusmanb / micropicodrive

Internal microdrive replacement for the Sinclair QL
MIT License
13 stars 1 forks source link

MDVTools #1

Closed kladogen closed 4 months ago

kladogen commented 11 months ago

Hi, I am working on something similar to your project. I'm trying to understand why you have the following checks in file MicroDriveFile.cs :

if (currentBlock.Header.SectorNumber != FileMap[0].SectorNumber)
    throw new FileNotFoundException($"Cannot find file sector {FileMap[0].SectorNumber}");

if (currentBlock.Record.FileBlock != FileMap[0].FileBlock || **currentBlock.Record.FileNumber != FileMap[0].FileNumber**)
    throw new FileNotFoundException($"Cannot find file sector {FileMap[0].SectorNumber}");

and

if (currentBlock.Header.SectorNumber != FileMap[buc].SectorNumber) throw new FileNotFoundException($"Cannot find file sector {FileMap[buc].SectorNumber}");

if (currentBlock.Record.FileBlock != FileMap[buc].FileBlock || currentBlock.Record.FileNumber != FileMap[buc].FileNumber) throw new FileNotFoundException($"Cannot find file sector {FileMap[buc].SectorNumber}");

For some reason the following checks: *currentBlock.Record.FileNumber != FileMap[0].FileNumber and if (currentBlock.Record.FileBlock != FileMap[buc].FileBlock || currentBlock.Record.FileNumber != FileMap[buc].FileNumber) produce and error for an mdv that works on the QL.

When I remove them it loads the MDV.

Also I tried to export files from various MDV but with no success.

Regards

Antonis

gusmanb commented 11 months ago

If the check fails then the cartridges are corrupt, in fact I have seen already one cartridge like that and is a cartridge that is copy-protected.

There are two reasons for those checks. The first is on the line before the checks: var currentBlock = Sectors.Where(s => s.Header.HeaderFlag == 0xFF && s.Header.SectorNumber == FileMap[0].SectorNumber).FirstOrDefault();

MicroDriveSector is a struct, so its default value is not null but an empty struct, to check if it was or was not found I need to compare the result content with what I was searching for, if the sector was not found all will be initialized to zeros and thus the sector number will not match, that explains the first check.

The second reason and second check is to test the integrity of the cartridge. If you are familiar with the format of the microdrive then you know that sector 0 contains a map of sectors with the filenumber/fileblock of each one, and each sector also contains in the record header the filenumber and the fileblock, arguably if the map does not match what the sector header says then the sector has been corrupted.

Said that, what I have found is that some clever programmers used that as a copy protection: they protected the cartridges by writting those headers without the file/block number, it is set to zero, and it seems the QL ignores that data, it only uses the map at sector zero. If you try to copy the files from one microdrive to another the headers are regenerated and then when the executable runs, checks those headers, if it finds that they are correct then it knows that it has been copied and refuses to run.

As the target of the program is to manipulate cartridge images and when a new image is exported I reconstruct that info like the QL does I do not plan to add support for that particular case.

Finally, about the export, it works but has a "little" bug, the files are always stored in the exec path, it ignores the path you select, only the file name is used. I already have corrected it, it's in the repo, if you pull the changes you will get them.

Cheers.

kladogen commented 11 months ago

Hi,

To be precise I don't really understand what is happening with:

currentBlock.Record.FileNumber != FileMap[0].FileNumber

The sector map on sector 0 holds a FileNumber and a BlockNumber for sectors 0-254. So If we want to use sector 253 for a file with FileNumber 1 and one block, we need to write at the pair of bytes before the last, the FileNumber (1) and the BlockNumber (0). However in this case, an exception occurs at currentBlock.Record.FileNumber != FileMap[0].FileNumber since the file number is 1 but the FileMap[0].FileNumber is 253 and the check fails with a message "Cannot find file sector 253".

If I disable the check, then the next check fails but if I disable that also the MDV loads correctly and shows the files.

Is there something that I have understood mistakenly with sector 0?

Thanks

Antonis

gusmanb commented 11 months ago

Hi,

To be precise I don't really understand what is happening with:

currentBlock.Record.FileNumber != FileMap[0].FileNumber

The sector map on sector 0 holds a FileNumber and a BlockNumber for sectors 0-254. So If we want to use sector 253 for a file with FileNumber 1 and one block, we need to write at the pair of bytes before the last, the FileNumber (1) and the BlockNumber (0). However in this case, an exception occurs at currentBlock.Record.FileNumber != FileMap[0].FileNumber since the file number is 1 but the FileMap[0].FileNumber is 253 and the check fails with a message "Cannot find file sector 253".

If I disable the check, then the next check fails but if I disable that also the MDV loads correctly and shows the files.

Is there something that I have understood mistakenly with sector 0?

Thanks

Antonis

Hi.

This is already explained in my previous answer. I'm checking for integrity of the sectors.

This is the microdrive format in a real cartridge:

imagen

As you can see, after the sector header there is a second header, the block header. This header contains the file number and the block number:

imagen

What I'm checking there is that what is in the block header matches what is in the sector map. If these don't match then the cartridge image should be corrupted, but there are copy-protected cartridges that intentionally malform that header and the QL seems to not to check that header when reading data:

Said that, what I have found is that some clever programmers used that as a copy protection: they protected the cartridges by writting those headers without the file/block number, it is set to zero, and it seems the QL ignores that data, it only uses the map at sector zero. If you try to copy the files from one microdrive to another the headers are regenerated and then when the executable runs, checks those headers, if it finds that they are correct then it knows that it has been copied and refuses to run.

If you need more info about the format of the microdrive I recommend you to read the "QL advanced user guide", it contains a full description of the format in appendix D.

Cheers.

kladogen commented 11 months ago

Hi,

I will check the 253 sector contents then!

Regards,

Antonis

kladogen commented 11 months ago

Thanks, I did not notice that detail for the Header Block in the sector data!