mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Refactor image classes and split them to smaller files.
This commit is contained in:
575
.idea/.idea.DiscImageChef/.idea/contentModel.xml
generated
575
.idea/.idea.DiscImageChef/.idea/contentModel.xml
generated
@@ -485,60 +485,531 @@
|
||||
</e>
|
||||
</e>
|
||||
<e p="DiscImageChef.DiscImages" t="IncludeRecursive">
|
||||
<e p="Alcohol120.cs" t="Include" />
|
||||
<e p="Anex86.cs" t="Include" />
|
||||
<e p="Apple2MG.cs" t="Include" />
|
||||
<e p="AppleDOS.cs" t="Include" />
|
||||
<e p="AppleNIB.cs" t="Include" />
|
||||
<e p="Apridisk.cs" t="Include" />
|
||||
<e p="BLU.cs" t="Include" />
|
||||
<e p="BlindWrite4.cs" t="Include" />
|
||||
<e p="BlindWrite5.cs" t="Include" />
|
||||
<e p="CDRDAO.cs" t="Include" />
|
||||
<e p="CDRWin.cs" t="Include" />
|
||||
<e p="CHD.cs" t="Include" />
|
||||
<e p="CPCDSK.cs" t="Include" />
|
||||
<e p="CisCopy.cs" t="Include" />
|
||||
<e p="CloneCD.cs" t="Include" />
|
||||
<e p="CopyQM.cs" t="Include" />
|
||||
<e p="D88.cs" t="Include" />
|
||||
<e p="DART.cs" t="Include" />
|
||||
<e p="DIM.cs" t="Include" />
|
||||
<e p="DiscFerret.cs" t="Include" />
|
||||
<e p="Alcohol120" t="Include">
|
||||
<e p="Alcohol120.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Anex86" t="Include">
|
||||
<e p="Anex86.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Apple2MG" t="Include">
|
||||
<e p="Apple2MG.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="AppleDOS" t="Include">
|
||||
<e p="AppleDOS.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="AppleNIB" t="Include">
|
||||
<e p="AppleNIB.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Apridisk" t="Include">
|
||||
<e p="Apridisk.cs" t="Include" />
|
||||
<e p="Compression.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="BLU" t="Include">
|
||||
<e p="BLU.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="BlindWrite4" t="Include">
|
||||
<e p="BlindWrite4.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
</e>
|
||||
<e p="BlindWrite5" t="Include">
|
||||
<e p="BlindWrite5.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CDRDAO" t="Include">
|
||||
<e p="CDRDAO.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CDRWin" t="Include">
|
||||
<e p="CDRWin.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CHD" t="Include">
|
||||
<e p="CHD.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CPCDSK" t="Include">
|
||||
<e p="CPCDSK.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CisCopy" t="Include">
|
||||
<e p="CisCopy.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CloneCD" t="Include">
|
||||
<e p="CloneCD.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="CopyQM" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="CopyQM.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="D88" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="D88.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DART" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DART.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DIM" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DIM.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DiscFerret" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DiscFerret.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DiscImageChef" t="Include">
|
||||
<e p="ClauniaSubchannelTransform.cs" t="Include" />
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DiscImageChef.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Verify.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DiscImageChef.DiscImages.csproj" t="IncludeRecursive" />
|
||||
<e p="DiscImageChef.cs" t="Include" />
|
||||
<e p="DiscJuggler.cs" t="Include" />
|
||||
<e p="DiskCopy42.cs" t="Include" />
|
||||
<e p="DriDiskCopy.cs" t="Include" />
|
||||
<e p="GDI.cs" t="Include" />
|
||||
<e p="HDCopy.cs" t="Include" />
|
||||
<e p="IMD.cs" t="Include" />
|
||||
<e p="KryoFlux.cs" t="Include" />
|
||||
<e p="MaxiDisk.cs" t="Include" />
|
||||
<e p="NDIF.cs" t="Include" />
|
||||
<e p="NHDr0.cs" t="Include" />
|
||||
<e p="Nero.cs" t="Include" />
|
||||
<e p="Parallels.cs" t="Include" />
|
||||
<e p="PartClone.cs" t="Include" />
|
||||
<e p="Partimage.cs" t="Include" />
|
||||
<e p="QCOW.cs" t="Include" />
|
||||
<e p="QCOW2.cs" t="Include" />
|
||||
<e p="QED.cs" t="Include" />
|
||||
<e p="RayDIM.cs" t="Include" />
|
||||
<e p="DiscJuggler" t="Include">
|
||||
<e p="DiscJuggler.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DiskCopy42" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DiskCopy42.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="DriDiskCopy" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="DriDiskCopy.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="GDI" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="GDI.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="HDCopy" t="Include">
|
||||
<e p="HDCopy.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="IMD" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="IMD.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="KryoFlux" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="KryoFlux.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="MaxiDisk" t="Include">
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="MaxiDisk.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="NDIF" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="NDIF.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="NHDr0" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="NHDr0.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Nero" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Nero.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Parallels" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Parallels.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="PartClone" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="PartClone.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Partimage" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Partimage.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="QCOW" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="QCOW.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="QCOW2" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="QCOW2.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="QED" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="QED.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="RayDIM" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="RayDIM.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Register.cs" t="Include" />
|
||||
<e p="RsIde.cs" t="Include" />
|
||||
<e p="SaveDskF.cs" t="Include" />
|
||||
<e p="SuperCardPro.cs" t="Include" />
|
||||
<e p="T98.cs" t="Include" />
|
||||
<e p="TeleDisk.cs" t="Include" />
|
||||
<e p="UDIF.cs" t="Include" />
|
||||
<e p="UkvFdi.cs" t="Include" />
|
||||
<e p="VDI.cs" t="Include" />
|
||||
<e p="VHD.cs" t="Include" />
|
||||
<e p="VHDX.cs" t="Include" />
|
||||
<e p="VMware.cs" t="Include" />
|
||||
<e p="Virtual98.cs" t="Include" />
|
||||
<e p="ZZZRawImage.cs" t="Include" />
|
||||
<e p="RsIde" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="RsIde.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="SaveDskF" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="SaveDskF.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="SuperCardPro" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="SuperCardPro.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="T98" t="Include">
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="T98.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="TeleDisk" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="TeleDisk.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="UDIF" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="UDIF.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="UkvFdi" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="UkvFdi.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
</e>
|
||||
<e p="VDI" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Enums.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="VDI.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="VHD" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="VHD.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="VHDX" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="VHDX.cs" t="Include" />
|
||||
</e>
|
||||
<e p="VMware" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="VMware.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="Virtual98" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Structs.cs" t="Include" />
|
||||
<e p="Unsupported.cs" t="Include" />
|
||||
<e p="Virtual98.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
</e>
|
||||
<e p="ZZZRawImage" t="Include">
|
||||
<e p="Constants.cs" t="Include" />
|
||||
<e p="Helpers.cs" t="Include" />
|
||||
<e p="Identify.cs" t="Include" />
|
||||
<e p="Properties.cs" t="Include" />
|
||||
<e p="Read.cs" t="Include" />
|
||||
<e p="Write.cs" t="Include" />
|
||||
<e p="ZZZRawImage.cs" t="Include" />
|
||||
</e>
|
||||
<e p="bin" t="ExcludeRecursive" />
|
||||
<e p="obj" t="ExcludeRecursive">
|
||||
<e p="Debug" t="Include">
|
||||
|
||||
88
DiscImageChef.DiscImages/Alcohol120/Alcohol120.cs
Normal file
88
DiscImageChef.DiscImages/Alcohol120/Alcohol120.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Alcohol120.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120 : IWritableImage
|
||||
{
|
||||
AlcoholFooter alcFooter;
|
||||
IFilter alcImage;
|
||||
Dictionary<int, AlcoholSession> alcSessions;
|
||||
Dictionary<int, Dictionary<int, AlcoholTrack>> alcToc;
|
||||
Dictionary<int, AlcoholTrackExtra> alcTrackExtras;
|
||||
Dictionary<int, AlcoholTrack> alcTracks;
|
||||
byte[] bca;
|
||||
FileStream descriptorStream;
|
||||
byte[] dmi;
|
||||
byte[] fullToc;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
bool isDvd;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
byte[] pfi;
|
||||
Dictionary<byte, byte> trackFlags;
|
||||
List<Track> writingTracks;
|
||||
|
||||
public Alcohol120()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
40
DiscImageChef.DiscImages/Alcohol120/Constants.cs
Normal file
40
DiscImageChef.DiscImages/Alcohol120/Constants.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
readonly byte[] alcoholSignature =
|
||||
{0x4d, 0x45, 0x44, 0x49, 0x41, 0x20, 0x44, 0x45, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x4f, 0x52};
|
||||
}
|
||||
}
|
||||
69
DiscImageChef.DiscImages/Alcohol120/Enums.cs
Normal file
69
DiscImageChef.DiscImages/Alcohol120/Enums.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum AlcoholMediumType : ushort
|
||||
{
|
||||
CD = 0x00,
|
||||
CDR = 0x01,
|
||||
CDRW = 0x02,
|
||||
DVD = 0x10,
|
||||
DVDR = 0x12
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
enum AlcoholTrackMode : byte
|
||||
{
|
||||
NoData = 0x00,
|
||||
DVD = 0x02,
|
||||
Audio = 0xA9,
|
||||
Mode1 = 0xAA,
|
||||
Mode2 = 0xAB,
|
||||
Mode2F1 = 0xEC,
|
||||
Mode2F2 = 0xED,
|
||||
Mode2F1Alt = 0xAC,
|
||||
Mode2F2Alt = 0xAD
|
||||
}
|
||||
|
||||
enum AlcoholSubchannelMode : byte
|
||||
{
|
||||
None = 0x00,
|
||||
Interleaved = 0x08
|
||||
}
|
||||
}
|
||||
}
|
||||
157
DiscImageChef.DiscImages/Alcohol120/Helpers.cs
Normal file
157
DiscImageChef.DiscImages/Alcohol120/Helpers.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
static ushort AlcoholTrackModeToBytesPerSector(AlcoholTrackMode trackMode)
|
||||
{
|
||||
switch(trackMode)
|
||||
{
|
||||
case AlcoholTrackMode.Audio:
|
||||
case AlcoholTrackMode.Mode1:
|
||||
case AlcoholTrackMode.Mode2:
|
||||
case AlcoholTrackMode.Mode2F1:
|
||||
case AlcoholTrackMode.Mode2F2:
|
||||
case AlcoholTrackMode.Mode2F2Alt:
|
||||
case AlcoholTrackMode.Mode2F1Alt: return 2352;
|
||||
case AlcoholTrackMode.DVD: return 2048;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ushort AlcoholTrackModeToCookedBytesPerSector(AlcoholTrackMode trackMode)
|
||||
{
|
||||
switch(trackMode)
|
||||
{
|
||||
case AlcoholTrackMode.Mode1:
|
||||
case AlcoholTrackMode.Mode2F1:
|
||||
case AlcoholTrackMode.Mode2F1Alt: return 2048;
|
||||
case AlcoholTrackMode.Mode2F2:
|
||||
case AlcoholTrackMode.Mode2F2Alt: return 2324;
|
||||
case AlcoholTrackMode.Mode2: return 2336;
|
||||
case AlcoholTrackMode.Audio: return 2352;
|
||||
case AlcoholTrackMode.DVD: return 2048;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static TrackType AlcoholTrackTypeToTrackType(AlcoholTrackMode trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case AlcoholTrackMode.Mode1: return TrackType.CdMode1;
|
||||
case AlcoholTrackMode.Mode2F1:
|
||||
case AlcoholTrackMode.Mode2F1Alt: return TrackType.CdMode2Form1;
|
||||
case AlcoholTrackMode.Mode2F2:
|
||||
case AlcoholTrackMode.Mode2F2Alt: return TrackType.CdMode2Form2;
|
||||
case AlcoholTrackMode.Mode2: return TrackType.CdMode2Formless;
|
||||
case AlcoholTrackMode.Audio: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static MediaType AlcoholMediumTypeToMediaType(AlcoholMediumType discType)
|
||||
{
|
||||
switch(discType)
|
||||
{
|
||||
case AlcoholMediumType.CD: return MediaType.CD;
|
||||
case AlcoholMediumType.CDR: return MediaType.CDR;
|
||||
case AlcoholMediumType.CDRW: return MediaType.CDRW;
|
||||
case AlcoholMediumType.DVD: return MediaType.DVDROM;
|
||||
case AlcoholMediumType.DVDR: return MediaType.DVDR;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static AlcoholMediumType MediaTypeToAlcohol(MediaType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case MediaType.CD:
|
||||
case MediaType.CDDA:
|
||||
case MediaType.CDEG:
|
||||
case MediaType.CDG:
|
||||
case MediaType.CDI:
|
||||
case MediaType.CDMIDI:
|
||||
case MediaType.CDPLUS:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.CDROMXA:
|
||||
case MediaType.CDV:
|
||||
case MediaType.DTSCD:
|
||||
case MediaType.JaguarCD:
|
||||
case MediaType.MEGACD:
|
||||
case MediaType.PS1CD:
|
||||
case MediaType.PS2CD:
|
||||
case MediaType.SuperCDROM2:
|
||||
case MediaType.SVCD:
|
||||
case MediaType.SATURNCD:
|
||||
case MediaType.ThreeDO:
|
||||
case MediaType.VCD:
|
||||
case MediaType.VCDHD: return AlcoholMediumType.CD;
|
||||
case MediaType.CDR: return AlcoholMediumType.CDR;
|
||||
case MediaType.CDRW:
|
||||
case MediaType.CDMRW: return AlcoholMediumType.CDRW;
|
||||
case MediaType.DVDR:
|
||||
case MediaType.DVDRW:
|
||||
case MediaType.DVDPR:
|
||||
case MediaType.DVDRDL:
|
||||
case MediaType.DVDRWDL:
|
||||
case MediaType.DVDPRDL:
|
||||
case MediaType.DVDPRWDL: return AlcoholMediumType.DVDR;
|
||||
default: return AlcoholMediumType.DVD;
|
||||
}
|
||||
}
|
||||
|
||||
static AlcoholTrackMode TrackTypeToAlcohol(TrackType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case TrackType.Audio: return AlcoholTrackMode.Audio;
|
||||
case TrackType.CdMode1: return AlcoholTrackMode.Mode1;
|
||||
case TrackType.CdMode2Formless: return AlcoholTrackMode.Mode2;
|
||||
case TrackType.CdMode2Form1: return AlcoholTrackMode.Mode2F1;
|
||||
case TrackType.CdMode2Form2: return AlcoholTrackMode.Mode2F2;
|
||||
default: return AlcoholTrackMode.DVD;
|
||||
}
|
||||
}
|
||||
|
||||
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector)
|
||||
{
|
||||
return ((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75));
|
||||
}
|
||||
}
|
||||
}
|
||||
59
DiscImageChef.DiscImages/Alcohol120/Identify.cs
Normal file
59
DiscImageChef.DiscImages/Alcohol120/Identify.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if(stream.Length < 88) return false;
|
||||
|
||||
byte[] hdr = new byte[88];
|
||||
stream.Read(hdr, 0, 88);
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(88);
|
||||
Marshal.Copy(hdr, 0, hdrPtr, 88);
|
||||
AlcoholHeader header = (AlcoholHeader)Marshal.PtrToStructure(hdrPtr, typeof(AlcoholHeader));
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
|
||||
return header.signature.SequenceEqual(alcoholSignature);
|
||||
}
|
||||
}
|
||||
}
|
||||
141
DiscImageChef.DiscImages/Alcohol120/Properties.cs
Normal file
141
DiscImageChef.DiscImages/Alcohol120/Properties.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
public string Name => "Alcohol 120% Media Descriptor Structure";
|
||||
public Guid Id => new Guid("A78FBEBA-0307-4915-BDE3-B8A3B57F843F");
|
||||
|
||||
public string Format => "Alcohol 120% Media Descriptor Structure";
|
||||
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
|
||||
public List<Track> Tracks
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Track> tracks = new List<Track>();
|
||||
|
||||
foreach(AlcoholTrack alcTrack in alcTracks.Values)
|
||||
{
|
||||
ushort sessionNo =
|
||||
(from session in Sessions
|
||||
where alcTrack.point >= session.StartTrack || alcTrack.point <= session.EndTrack
|
||||
select session.SessionSequence).FirstOrDefault();
|
||||
|
||||
if(!alcTrackExtras.TryGetValue(alcTrack.point, out AlcoholTrackExtra alcExtra)) continue;
|
||||
|
||||
Track dicTrack = new Track
|
||||
{
|
||||
Indexes = new Dictionary<int, ulong> {{1, alcTrack.startLba}},
|
||||
TrackStartSector = alcTrack.startLba,
|
||||
TrackEndSector = alcTrack.startLba + alcExtra.sectors - 1,
|
||||
TrackPregap = alcExtra.pregap,
|
||||
TrackSession = sessionNo,
|
||||
TrackSequence = alcTrack.point,
|
||||
TrackType = AlcoholTrackTypeToTrackType(alcTrack.mode),
|
||||
TrackFilter = alcImage,
|
||||
TrackFile = alcImage.GetFilename(),
|
||||
TrackFileOffset = alcTrack.startOffset,
|
||||
TrackFileType = "BINARY",
|
||||
TrackRawBytesPerSector = alcTrack.sectorSize,
|
||||
TrackBytesPerSector = AlcoholTrackModeToCookedBytesPerSector(alcTrack.mode)
|
||||
};
|
||||
|
||||
switch(alcTrack.subMode)
|
||||
{
|
||||
case AlcoholSubchannelMode.Interleaved:
|
||||
dicTrack.TrackSubchannelFilter = alcImage;
|
||||
dicTrack.TrackSubchannelFile = alcImage.GetFilename();
|
||||
dicTrack.TrackSubchannelOffset = alcTrack.startOffset;
|
||||
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
|
||||
break;
|
||||
case AlcoholSubchannelMode.None:
|
||||
dicTrack.TrackSubchannelType = TrackSubchannelType.None;
|
||||
break;
|
||||
}
|
||||
|
||||
tracks.Add(dicTrack);
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Session> Sessions { get; private set; }
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags =>
|
||||
new[] {MediaTagType.CD_FullTOC, MediaTagType.DVD_BCA, MediaTagType.DVD_DMI, MediaTagType.DVD_PFI};
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags =>
|
||||
new[]
|
||||
{
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
|
||||
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader,
|
||||
SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdSectorSubchannel
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.BDRXL, MediaType.CBHD,
|
||||
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
|
||||
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
|
||||
MediaType.CDV, MediaType.DVDDownload, MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW,
|
||||
MediaType.DVDPRWDL, MediaType.DVDR, MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM,
|
||||
MediaType.DVDRW, MediaType.DVDRWDL, MediaType.EVD, MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD,
|
||||
MediaType.HDDVDR, MediaType.HDDVDRAM, MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW,
|
||||
MediaType.HDDVDRWDL, MediaType.HDVMD, MediaType.HVD, MediaType.JaguarCD, MediaType.MEGACD,
|
||||
MediaType.PD650, MediaType.PD650_WORM, MediaType.PS1CD, MediaType.PS2CD, MediaType.PS2DVD,
|
||||
MediaType.PS3BD, MediaType.PS3DVD, MediaType.PS4BD, MediaType.SuperCDROM2, MediaType.SVCD,
|
||||
MediaType.SVOD, MediaType.SATURNCD, MediaType.ThreeDO, MediaType.UDO, MediaType.UDO2,
|
||||
MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD, MediaType.VCDHD, MediaType.NeoGeoCD, MediaType.PCFX
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".mds"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
120
DiscImageChef.DiscImages/Alcohol120/Structs.cs
Normal file
120
DiscImageChef.DiscImages/Alcohol120/Structs.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] signature;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public byte[] version;
|
||||
public AlcoholMediumType type;
|
||||
public ushort sessions;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public ushort[] unknown1;
|
||||
public ushort bcaLength;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown2;
|
||||
public uint bcaOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public uint[] unknown3;
|
||||
public uint structuresOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown4;
|
||||
public uint sessionOffset;
|
||||
public uint dpmOffset;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholSession
|
||||
{
|
||||
public int sessionStart;
|
||||
public int sessionEnd;
|
||||
public ushort sessionSequence;
|
||||
public byte allBlocks;
|
||||
public byte nonTrackBlocks;
|
||||
public ushort firstTrack;
|
||||
public ushort lastTrack;
|
||||
public uint unknown;
|
||||
public uint trackOffset;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholTrack
|
||||
{
|
||||
public AlcoholTrackMode mode;
|
||||
public AlcoholSubchannelMode subMode;
|
||||
public byte adrCtl;
|
||||
public byte tno;
|
||||
public byte point;
|
||||
public byte min;
|
||||
public byte sec;
|
||||
public byte frame;
|
||||
public byte zero;
|
||||
public byte pmin;
|
||||
public byte psec;
|
||||
public byte pframe;
|
||||
public uint extraOffset;
|
||||
public ushort sectorSize;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)]
|
||||
public byte[] unknown;
|
||||
public uint startLba;
|
||||
public ulong startOffset;
|
||||
public uint files;
|
||||
public uint footerOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public byte[] unknown2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholTrackExtra
|
||||
{
|
||||
public uint pregap;
|
||||
public uint sectors;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholFooter
|
||||
{
|
||||
public uint filenameOffset;
|
||||
public uint widechar;
|
||||
public uint unknown1;
|
||||
public uint unknown2;
|
||||
}
|
||||
}
|
||||
}
|
||||
985
DiscImageChef.DiscImages/Alcohol120/Write.cs
Normal file
985
DiscImageChef.DiscImages/Alcohol120/Write.cs
Normal file
@@ -0,0 +1,985 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes Alcohol 120% disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Decoders.CD;
|
||||
using Schemas;
|
||||
using TrackType = DiscImageChef.CommonTypes.Enums.TrackType;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Alcohol120
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try
|
||||
{
|
||||
descriptorStream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
|
||||
imageStream =
|
||||
new
|
||||
FileStream(Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path)) + ".mdf",
|
||||
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo.MediaType = mediaType;
|
||||
|
||||
switch(mediaType)
|
||||
{
|
||||
case MediaType.CD:
|
||||
case MediaType.CDDA:
|
||||
case MediaType.CDEG:
|
||||
case MediaType.CDG:
|
||||
case MediaType.CDI:
|
||||
case MediaType.CDMIDI:
|
||||
case MediaType.CDMRW:
|
||||
case MediaType.CDPLUS:
|
||||
case MediaType.CDR:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.CDROMXA:
|
||||
case MediaType.CDRW:
|
||||
case MediaType.CDV:
|
||||
case MediaType.DTSCD:
|
||||
case MediaType.JaguarCD:
|
||||
case MediaType.MEGACD:
|
||||
case MediaType.PS1CD:
|
||||
case MediaType.PS2CD:
|
||||
case MediaType.SuperCDROM2:
|
||||
case MediaType.SVCD:
|
||||
case MediaType.SATURNCD:
|
||||
case MediaType.ThreeDO:
|
||||
case MediaType.VCD:
|
||||
case MediaType.VCDHD:
|
||||
isDvd = false;
|
||||
break;
|
||||
default:
|
||||
isDvd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
trackFlags = new Dictionary<byte, byte>();
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case MediaTagType.CD_FullTOC:
|
||||
if(isDvd)
|
||||
{
|
||||
ErrorMessage = $"Unsupported media tag {tag} for medium type {imageInfo.MediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] fullTocSize = BigEndianBitConverter.GetBytes((short)data.Length);
|
||||
fullToc = new byte[data.Length + 2];
|
||||
Array.Copy(data, 0, fullToc, 2, data.Length);
|
||||
fullToc[0] = fullTocSize[0];
|
||||
fullToc[1] = fullTocSize[1];
|
||||
return true;
|
||||
case MediaTagType.DVD_PFI:
|
||||
if(!isDvd)
|
||||
{
|
||||
ErrorMessage = $"Unsupported media tag {tag} for medium type {imageInfo.MediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
pfi = data;
|
||||
return true;
|
||||
case MediaTagType.DVD_DMI:
|
||||
if(!isDvd)
|
||||
{
|
||||
ErrorMessage = $"Unsupported media tag {tag} for medium type {imageInfo.MediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
dmi = data;
|
||||
return true;
|
||||
case MediaTagType.DVD_BCA:
|
||||
if(!isDvd)
|
||||
{
|
||||
ErrorMessage = $"Unsupported media tag {tag} for medium type {imageInfo.MediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
bca = data;
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported media tag {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, 0, data.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(track.TrackSubchannelType)
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
imageStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
imageStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)),
|
||||
SeekOrigin.Begin);
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
imageStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector);
|
||||
imageStream.Position += 96;
|
||||
}
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = "Invalid subchannel mode for this sector";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
imageStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
imageStream.Seek((long)(track.TrackFileOffset + (i + sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ulong currentDataOffset = 0;
|
||||
|
||||
writingTracks = new List<Track>();
|
||||
foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
|
||||
{
|
||||
Track newTrack = track;
|
||||
uint subchannelSize;
|
||||
switch(track.TrackSubchannelType)
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
subchannelSize = 0;
|
||||
break;
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
subchannelSize = 96;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported subchannel type {track.TrackSubchannelType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
newTrack.TrackFileOffset = currentDataOffset;
|
||||
|
||||
currentDataOffset += (ulong)(newTrack.TrackRawBytesPerSector + subchannelSize) *
|
||||
(newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
|
||||
writingTracks.Add(newTrack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
byte sessions = byte.MinValue;
|
||||
|
||||
foreach(Track t in writingTracks)
|
||||
if(t.TrackSession > byte.MinValue)
|
||||
sessions = (byte)t.TrackSession;
|
||||
|
||||
AlcoholHeader header = new AlcoholHeader
|
||||
{
|
||||
signature = alcoholSignature,
|
||||
version = new byte[] {1, 5},
|
||||
type = MediaTypeToAlcohol(imageInfo.MediaType),
|
||||
sessions = sessions,
|
||||
structuresOffset = (uint)(pfi == null ? 0 : 96),
|
||||
sessionOffset = (uint)(pfi == null ? 96 : 4196),
|
||||
unknown1 = new ushort[2],
|
||||
unknown2 = new uint[2],
|
||||
unknown3 = new uint[6],
|
||||
unknown4 = new uint[3]
|
||||
};
|
||||
// Alcohol sets this always, Daemon Tool expects this
|
||||
header.unknown1[0] = 2;
|
||||
|
||||
alcSessions = new Dictionary<int, AlcoholSession>();
|
||||
alcTracks = new Dictionary<int, AlcoholTrack>();
|
||||
alcToc = new Dictionary<int, Dictionary<int, AlcoholTrack>>();
|
||||
writingTracks = writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).ToList();
|
||||
alcTrackExtras = new Dictionary<int, AlcoholTrackExtra>();
|
||||
long currentTrackOffset = header.sessionOffset + Marshal.SizeOf(typeof(AlcoholSession)) * sessions;
|
||||
|
||||
FullTOC.CDFullTOC? decodedToc = FullTOC.Decode(fullToc);
|
||||
|
||||
long currentExtraOffset = currentTrackOffset;
|
||||
for(int i = 1; i <= sessions; i++)
|
||||
if(decodedToc.HasValue)
|
||||
currentExtraOffset += Marshal.SizeOf(typeof(AlcoholTrack)) *
|
||||
decodedToc.Value.TrackDescriptors.Count(t => t.SessionNumber == i);
|
||||
else
|
||||
{
|
||||
currentExtraOffset += Marshal.SizeOf(typeof(AlcoholTrack)) * 3;
|
||||
currentExtraOffset += Marshal.SizeOf(typeof(AlcoholTrack)) *
|
||||
writingTracks.Count(t => t.TrackSession == i);
|
||||
if(i < sessions) currentExtraOffset += Marshal.SizeOf(typeof(AlcoholTrack)) * 2;
|
||||
}
|
||||
|
||||
long footerOffset = currentExtraOffset + Marshal.SizeOf(typeof(AlcoholTrackExtra)) * writingTracks.Count;
|
||||
if(bca != null)
|
||||
{
|
||||
header.bcaOffset = (uint)footerOffset;
|
||||
footerOffset += bca.Length;
|
||||
}
|
||||
|
||||
if(isDvd)
|
||||
{
|
||||
alcSessions.Add(1,
|
||||
new AlcoholSession
|
||||
{
|
||||
sessionEnd =
|
||||
(int)(writingTracks[0].TrackEndSector - writingTracks[0].TrackStartSector + 1),
|
||||
sessionSequence = 1,
|
||||
allBlocks = 1,
|
||||
nonTrackBlocks = 3,
|
||||
firstTrack = 1,
|
||||
lastTrack = 1,
|
||||
trackOffset = 4220
|
||||
});
|
||||
|
||||
footerOffset = 4300;
|
||||
if(bca != null) footerOffset += bca.Length;
|
||||
|
||||
alcTracks.Add(1,
|
||||
new AlcoholTrack
|
||||
{
|
||||
mode = AlcoholTrackMode.DVD,
|
||||
adrCtl = 20,
|
||||
point = 1,
|
||||
extraOffset =
|
||||
(uint)(writingTracks[0].TrackEndSector - writingTracks[0].TrackStartSector + 1),
|
||||
sectorSize = 2048,
|
||||
files = 1,
|
||||
footerOffset = (uint)footerOffset,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
|
||||
alcToc.Add(1, alcTracks);
|
||||
}
|
||||
else
|
||||
for(int i = 1; i <= sessions; i++)
|
||||
{
|
||||
Track firstTrack = writingTracks.First(t => t.TrackSession == i);
|
||||
Track lastTrack = writingTracks.Last(t => t.TrackSession == i);
|
||||
|
||||
alcSessions.Add(i,
|
||||
new AlcoholSession
|
||||
{
|
||||
sessionStart = (int)firstTrack.TrackStartSector - 150,
|
||||
sessionEnd = (int)lastTrack.TrackEndSector + 1,
|
||||
sessionSequence = (ushort)i,
|
||||
allBlocks =
|
||||
(byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i) ??
|
||||
writingTracks.Count(t => t.TrackSession == i) + 3),
|
||||
nonTrackBlocks =
|
||||
(byte)(decodedToc?.TrackDescriptors.Count(t => t.SessionNumber == i &&
|
||||
t.POINT >= 0xA0 &&
|
||||
t.POINT <= 0xAF) ??
|
||||
3),
|
||||
firstTrack = (ushort)firstTrack.TrackSequence,
|
||||
lastTrack = (ushort)lastTrack.TrackSequence,
|
||||
trackOffset = (uint)currentTrackOffset
|
||||
});
|
||||
|
||||
Dictionary<int, AlcoholTrack> thisSessionTracks = new Dictionary<int, AlcoholTrack>();
|
||||
trackFlags.TryGetValue((byte)firstTrack.TrackSequence, out byte firstTrackControl);
|
||||
trackFlags.TryGetValue((byte)lastTrack.TrackSequence, out byte lastTrackControl);
|
||||
if(firstTrackControl == 0 && firstTrack.TrackType != TrackType.Audio)
|
||||
firstTrackControl = (byte)CdFlags.DataTrack;
|
||||
if(lastTrackControl == 0 && lastTrack.TrackType != TrackType.Audio)
|
||||
lastTrackControl = (byte)CdFlags.DataTrack;
|
||||
(byte minute, byte second, byte frame) leadinPmsf = LbaToMsf(lastTrack.TrackEndSector + 1);
|
||||
|
||||
if(decodedToc.HasValue &&
|
||||
decodedToc.Value.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xA0 &&
|
||||
t.POINT <= 0xAF))
|
||||
foreach(FullTOC.TrackDataDescriptor tocTrk in
|
||||
decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xA0 &&
|
||||
t.POINT <= 0xAF))
|
||||
{
|
||||
thisSessionTracks.Add(tocTrk.POINT,
|
||||
new AlcoholTrack
|
||||
{
|
||||
adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL),
|
||||
tno = tocTrk.TNO,
|
||||
point = tocTrk.POINT,
|
||||
min = tocTrk.Min,
|
||||
sec = tocTrk.Sec,
|
||||
frame = tocTrk.Frame,
|
||||
zero = tocTrk.Zero,
|
||||
pmin = tocTrk.PMIN,
|
||||
psec = tocTrk.PSEC,
|
||||
pframe = tocTrk.PFRAME,
|
||||
mode = AlcoholTrackMode.NoData,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
currentTrackOffset += Marshal.SizeOf(typeof(AlcoholTrack));
|
||||
}
|
||||
else
|
||||
{
|
||||
thisSessionTracks.Add(0xA0, new AlcoholTrack
|
||||
{
|
||||
adrCtl = (byte)((1 << 4) + firstTrackControl),
|
||||
pmin = (byte)firstTrack.TrackSequence,
|
||||
mode = AlcoholTrackMode.NoData,
|
||||
point = 0xA0,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24],
|
||||
psec = (byte)(imageInfo.MediaType == MediaType.CDI
|
||||
? 0x10
|
||||
: writingTracks.Any(t => t.TrackType == TrackType.CdMode2Form1 ||
|
||||
t.TrackType == TrackType.CdMode2Form2 ||
|
||||
t.TrackType == TrackType.CdMode2Formless)
|
||||
? 0x20
|
||||
: 0)
|
||||
});
|
||||
|
||||
thisSessionTracks.Add(0xA1,
|
||||
new AlcoholTrack
|
||||
{
|
||||
adrCtl = (byte)((1 << 4) + lastTrackControl),
|
||||
pmin = (byte)lastTrack.TrackSequence,
|
||||
mode = AlcoholTrackMode.NoData,
|
||||
point = 0xA1,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
|
||||
thisSessionTracks.Add(0xA2,
|
||||
new AlcoholTrack
|
||||
{
|
||||
adrCtl = (byte)((1 << 4) + firstTrackControl),
|
||||
zero = 0,
|
||||
pmin = leadinPmsf.minute,
|
||||
psec = leadinPmsf.second,
|
||||
pframe = leadinPmsf.frame,
|
||||
mode = AlcoholTrackMode.NoData,
|
||||
point = 0xA2,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
currentTrackOffset += Marshal.SizeOf(typeof(AlcoholTrack)) * 3;
|
||||
}
|
||||
|
||||
foreach(Track track in writingTracks.Where(t => t.TrackSession == i).OrderBy(t => t.TrackSequence))
|
||||
{
|
||||
AlcoholTrack alcTrk = new AlcoholTrack();
|
||||
if(decodedToc.HasValue &&
|
||||
decodedToc.Value.TrackDescriptors.Any(t => t.SessionNumber == i &&
|
||||
t.POINT == track.TrackSequence))
|
||||
{
|
||||
FullTOC.TrackDataDescriptor tocTrk =
|
||||
decodedToc.Value.TrackDescriptors.First(t => t.SessionNumber == i &&
|
||||
t.POINT == track.TrackSequence);
|
||||
|
||||
alcTrk.adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL);
|
||||
alcTrk.tno = tocTrk.TNO;
|
||||
alcTrk.point = tocTrk.POINT;
|
||||
alcTrk.min = tocTrk.Min;
|
||||
alcTrk.sec = tocTrk.Sec;
|
||||
alcTrk.frame = tocTrk.Frame;
|
||||
alcTrk.zero = tocTrk.Zero;
|
||||
alcTrk.pmin = tocTrk.PMIN;
|
||||
alcTrk.psec = tocTrk.PSEC;
|
||||
alcTrk.pframe = tocTrk.PFRAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
(byte minute, byte second, byte frame) msf = LbaToMsf(track.TrackStartSector);
|
||||
trackFlags.TryGetValue((byte)track.TrackSequence, out byte trackControl);
|
||||
if(trackControl == 0 && track.TrackType != TrackType.Audio)
|
||||
trackControl = (byte)CdFlags.DataTrack;
|
||||
|
||||
alcTrk.adrCtl = (byte)((1 << 4) + trackControl);
|
||||
alcTrk.point = (byte)track.TrackSequence;
|
||||
alcTrk.zero = 0;
|
||||
alcTrk.pmin = msf.minute;
|
||||
alcTrk.psec = msf.second;
|
||||
alcTrk.pframe = msf.frame;
|
||||
}
|
||||
|
||||
alcTrk.mode = TrackTypeToAlcohol(track.TrackType);
|
||||
alcTrk.subMode = track.TrackSubchannelType != TrackSubchannelType.None
|
||||
? AlcoholSubchannelMode.Interleaved
|
||||
: AlcoholSubchannelMode.None;
|
||||
alcTrk.sectorSize = (ushort)(track.TrackRawBytesPerSector +
|
||||
(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0));
|
||||
alcTrk.startLba = (uint)track.TrackStartSector;
|
||||
alcTrk.startOffset = track.TrackFileOffset;
|
||||
alcTrk.files = 1;
|
||||
alcTrk.extraOffset = (uint)currentExtraOffset;
|
||||
alcTrk.footerOffset = (uint)footerOffset;
|
||||
// Alcohol seems to set that for all CD tracks
|
||||
// Daemon Tools expect it to be like this
|
||||
alcTrk.unknown = new byte[]
|
||||
{
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
alcTrk.unknown2 = new byte[24];
|
||||
|
||||
thisSessionTracks.Add((int)track.TrackSequence, alcTrk);
|
||||
|
||||
currentTrackOffset += Marshal.SizeOf(typeof(AlcoholTrack));
|
||||
currentExtraOffset += Marshal.SizeOf(typeof(AlcoholTrackExtra));
|
||||
|
||||
AlcoholTrackExtra trkExtra = new AlcoholTrackExtra
|
||||
{
|
||||
sectors = (uint)(track.TrackEndSector - track.TrackStartSector + 1)
|
||||
};
|
||||
|
||||
// When track mode changes there's a mandatory gap, Alcohol needs it
|
||||
if(track.TrackSequence == firstTrack.TrackSequence) trkExtra.pregap = 150;
|
||||
else if(thisSessionTracks.TryGetValue((int)(track.TrackSequence - 1),
|
||||
out AlcoholTrack previousTrack) &&
|
||||
alcTrackExtras.TryGetValue((int)(track.TrackSequence - 1),
|
||||
out AlcoholTrackExtra previousExtra) &&
|
||||
previousTrack.mode != alcTrk.mode)
|
||||
{
|
||||
previousExtra.sectors -= 150;
|
||||
trkExtra.pregap = 150;
|
||||
alcTrackExtras.Remove((int)(track.TrackSequence - 1));
|
||||
alcTrackExtras.Add((int)(track.TrackSequence - 1), previousExtra);
|
||||
}
|
||||
else trkExtra.pregap = 0;
|
||||
|
||||
alcTrackExtras.Add((int)track.TrackSequence, trkExtra);
|
||||
}
|
||||
|
||||
if(decodedToc.HasValue &&
|
||||
decodedToc.Value.TrackDescriptors.Any(t => t.SessionNumber == i && t.POINT >= 0xB0))
|
||||
foreach(FullTOC.TrackDataDescriptor tocTrk in
|
||||
decodedToc.Value.TrackDescriptors.Where(t => t.SessionNumber == i && t.POINT >= 0xB0))
|
||||
{
|
||||
thisSessionTracks.Add(tocTrk.POINT,
|
||||
new AlcoholTrack
|
||||
{
|
||||
adrCtl = (byte)((tocTrk.ADR << 4) + tocTrk.CONTROL),
|
||||
tno = tocTrk.TNO,
|
||||
point = tocTrk.POINT,
|
||||
min = tocTrk.Min,
|
||||
sec = tocTrk.Sec,
|
||||
frame = tocTrk.Frame,
|
||||
zero = tocTrk.Zero,
|
||||
pmin = tocTrk.PMIN,
|
||||
psec = tocTrk.PSEC,
|
||||
pframe = tocTrk.PFRAME,
|
||||
mode = AlcoholTrackMode.NoData,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
currentTrackOffset += Marshal.SizeOf(typeof(AlcoholTrack));
|
||||
}
|
||||
else if(i < sessions)
|
||||
{
|
||||
(byte minute, byte second, byte frame) leadoutAmsf =
|
||||
LbaToMsf(writingTracks.First(t => t.TrackSession == i + 1).TrackStartSector - 150);
|
||||
(byte minute, byte second, byte frame) leadoutPmsf =
|
||||
LbaToMsf(writingTracks.OrderBy(t => t.TrackSession).ThenBy(t => t.TrackSequence).Last()
|
||||
.TrackStartSector);
|
||||
|
||||
thisSessionTracks.Add(0xB0,
|
||||
new AlcoholTrack
|
||||
{
|
||||
point = 0xB0,
|
||||
adrCtl = 0x50,
|
||||
zero = 0,
|
||||
min = leadoutAmsf.minute,
|
||||
sec = leadoutAmsf.second,
|
||||
frame = leadoutAmsf.frame,
|
||||
pmin = leadoutPmsf.minute,
|
||||
psec = leadoutPmsf.second,
|
||||
pframe = leadoutPmsf.frame,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
|
||||
thisSessionTracks.Add(0xC0,
|
||||
new AlcoholTrack
|
||||
{
|
||||
point = 0xC0,
|
||||
adrCtl = 0x50,
|
||||
min = 128,
|
||||
pmin = 97,
|
||||
psec = 25,
|
||||
unknown = new byte[18],
|
||||
unknown2 = new byte[24]
|
||||
});
|
||||
|
||||
currentTrackOffset += Marshal.SizeOf(typeof(AlcoholTrack)) * 2;
|
||||
}
|
||||
|
||||
alcToc.Add(i, thisSessionTracks);
|
||||
}
|
||||
|
||||
alcFooter = new AlcoholFooter
|
||||
{
|
||||
filenameOffset = (uint)(footerOffset + Marshal.SizeOf(typeof(AlcoholFooter))),
|
||||
widechar = 1
|
||||
};
|
||||
|
||||
byte[] filename = Encoding.Unicode.GetBytes("*.mdf"); // Yup, Alcohol stores no filename but a wildcard.
|
||||
|
||||
IntPtr blockPtr;
|
||||
|
||||
// Write header
|
||||
descriptorStream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] block = new byte[Marshal.SizeOf(header)];
|
||||
blockPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
|
||||
Marshal.StructureToPtr(header, blockPtr, true);
|
||||
Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
Marshal.FreeHGlobal(blockPtr);
|
||||
descriptorStream.Write(block, 0, block.Length);
|
||||
|
||||
// Write DVD structures if pressent
|
||||
if(header.structuresOffset != 0)
|
||||
{
|
||||
if(dmi != null)
|
||||
{
|
||||
descriptorStream.Seek(header.structuresOffset, SeekOrigin.Begin);
|
||||
if(dmi.Length == 2052) descriptorStream.Write(dmi, 0, 2052);
|
||||
else if(dmi.Length == 2048)
|
||||
{
|
||||
descriptorStream.Write(new byte[] {0x08, 0x02, 0x00, 0x00}, 0, 4);
|
||||
descriptorStream.Write(dmi, 0, 2048);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Create fake PFI if none present
|
||||
if(pfi != null)
|
||||
{
|
||||
descriptorStream.Seek(header.structuresOffset + 2052, SeekOrigin.Begin);
|
||||
descriptorStream.Write(pfi, pfi.Length - 2048, 2048);
|
||||
}
|
||||
}
|
||||
|
||||
// Write sessions
|
||||
descriptorStream.Seek(header.sessionOffset, SeekOrigin.Begin);
|
||||
foreach(AlcoholSession session in alcSessions.Values)
|
||||
{
|
||||
block = new byte[Marshal.SizeOf(session)];
|
||||
blockPtr = Marshal.AllocHGlobal(Marshal.SizeOf(session));
|
||||
Marshal.StructureToPtr(session, blockPtr, true);
|
||||
Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
Marshal.FreeHGlobal(blockPtr);
|
||||
descriptorStream.Write(block, 0, block.Length);
|
||||
}
|
||||
|
||||
// Write tracks
|
||||
foreach(KeyValuePair<int, Dictionary<int, AlcoholTrack>> kvp in alcToc)
|
||||
{
|
||||
descriptorStream.Seek(alcSessions.First(t => t.Key == kvp.Key).Value.trackOffset, SeekOrigin.Begin);
|
||||
foreach(AlcoholTrack track in kvp.Value.Values)
|
||||
{
|
||||
block = new byte[Marshal.SizeOf(track)];
|
||||
blockPtr = Marshal.AllocHGlobal(Marshal.SizeOf(track));
|
||||
Marshal.StructureToPtr(track, blockPtr, true);
|
||||
Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
Marshal.FreeHGlobal(blockPtr);
|
||||
descriptorStream.Write(block, 0, block.Length);
|
||||
|
||||
if(isDvd) continue;
|
||||
|
||||
// Write extra
|
||||
long position = descriptorStream.Position;
|
||||
descriptorStream.Seek(track.extraOffset, SeekOrigin.Begin);
|
||||
if(alcTrackExtras.TryGetValue(track.point, out AlcoholTrackExtra extra))
|
||||
{
|
||||
block = new byte[Marshal.SizeOf(extra)];
|
||||
blockPtr = Marshal.AllocHGlobal(Marshal.SizeOf(extra));
|
||||
Marshal.StructureToPtr(extra, blockPtr, true);
|
||||
Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
Marshal.FreeHGlobal(blockPtr);
|
||||
descriptorStream.Write(block, 0, block.Length);
|
||||
}
|
||||
|
||||
descriptorStream.Seek(position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
// Write BCA
|
||||
if(bca != null)
|
||||
{
|
||||
descriptorStream.Seek(header.bcaOffset, SeekOrigin.Begin);
|
||||
descriptorStream.Write(bca, 0, bca.Length);
|
||||
}
|
||||
|
||||
// Write footer
|
||||
descriptorStream.Seek(footerOffset, SeekOrigin.Begin);
|
||||
block = new byte[Marshal.SizeOf(alcFooter)];
|
||||
blockPtr = Marshal.AllocHGlobal(Marshal.SizeOf(alcFooter));
|
||||
Marshal.StructureToPtr(alcFooter, blockPtr, true);
|
||||
Marshal.Copy(blockPtr, block, 0, block.Length);
|
||||
Marshal.FreeHGlobal(blockPtr);
|
||||
descriptorStream.Write(block, 0, block.Length);
|
||||
|
||||
// Write filename
|
||||
descriptorStream.Write(filename, 0, filename.Length);
|
||||
// Write filename null termination
|
||||
descriptorStream.Write(new byte[] {0, 0}, 0, 2);
|
||||
|
||||
descriptorStream.Flush();
|
||||
descriptorStream.Close();
|
||||
imageStream.Flush();
|
||||
imageStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
{
|
||||
if(data.Length != 1)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for track flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackFlags.Add((byte)track.TrackSequence, data[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != 96)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)) + track.TrackRawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags: return WriteSectorTag(data, sectorAddress, tag);
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % 96 != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
imageStream
|
||||
.Seek((long)(track.TrackFileOffset + (i + sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)) + track.TrackRawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
imageStream.Write(data, (int)(i * 96), 96);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,551 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Anex86.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public class Anex86 : IWritableImage
|
||||
{
|
||||
IFilter anexImageFilter;
|
||||
Anex86Header fdihdr;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Anex86()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Anex86 Disk Image";
|
||||
public Guid Id => new Guid("0410003E-6E7B-40E6-9328-BA5651ADF6B7");
|
||||
|
||||
public string Format => "Anex86 disk image";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
fdihdr = new Anex86Header();
|
||||
|
||||
if(stream.Length < Marshal.SizeOf(fdihdr)) return false;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf(fdihdr)];
|
||||
stream.Read(hdrB, 0, hdrB.Length);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hdrB, GCHandleType.Pinned);
|
||||
fdihdr = (Anex86Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Anex86Header));
|
||||
handle.Free();
|
||||
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.unknown = {0}", fdihdr.unknown);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.hddtype = {0}", fdihdr.hddtype);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.hdrSize = {0}", fdihdr.hdrSize);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.dskSize = {0}", fdihdr.dskSize);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.bps = {0}", fdihdr.bps);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.spt = {0}", fdihdr.spt);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.heads = {0}", fdihdr.heads);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.cylinders = {0}", fdihdr.cylinders);
|
||||
|
||||
return stream.Length == fdihdr.hdrSize + fdihdr.dskSize &&
|
||||
fdihdr.dskSize == fdihdr.bps * fdihdr.spt * fdihdr.heads * fdihdr.cylinders;
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
fdihdr = new Anex86Header();
|
||||
|
||||
if(stream.Length < Marshal.SizeOf(fdihdr)) return false;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf(fdihdr)];
|
||||
stream.Read(hdrB, 0, hdrB.Length);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hdrB, GCHandleType.Pinned);
|
||||
fdihdr = (Anex86Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Anex86Header));
|
||||
handle.Free();
|
||||
|
||||
imageInfo.MediaType = Geometry.GetMediaType(((ushort)fdihdr.cylinders, (byte)fdihdr.heads,
|
||||
(ushort)fdihdr.spt, (uint)fdihdr.bps, MediaEncoding.MFM,
|
||||
false));
|
||||
if(imageInfo.MediaType == MediaType.Unknown) imageInfo.MediaType = MediaType.GENERIC_HDD;
|
||||
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "MediaType: {0}", imageInfo.MediaType);
|
||||
|
||||
imageInfo.ImageSize = (ulong)fdihdr.dskSize;
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = (ulong)(fdihdr.cylinders * fdihdr.heads * fdihdr.spt);
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
imageInfo.SectorSize = (uint)fdihdr.bps;
|
||||
imageInfo.Cylinders = (uint)fdihdr.cylinders;
|
||||
imageInfo.Heads = (uint)fdihdr.heads;
|
||||
imageInfo.SectorsPerTrack = (uint)fdihdr.spt;
|
||||
|
||||
anexImageFilter = imageFilter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
Stream stream = anexImageFilter.GetDataForkStream();
|
||||
|
||||
stream.Seek((long)((ulong)fdihdr.hdrSize + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
|
||||
stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
// TODO: Test with real hardware to see real supported media
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.IBM23FD, MediaType.ECMA_66, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9,
|
||||
MediaType.ACORN_525_SS_SD_40, MediaType.ACORN_525_SS_DD_40, MediaType.ATARI_525_SD,
|
||||
MediaType.ATARI_525_DD, MediaType.ATARI_525_ED, MediaType.DOS_525_DS_DD_8, MediaType.DOS_525_DS_DD_9,
|
||||
MediaType.ECMA_70, MediaType.Apricot_35, MediaType.RX01, MediaType.RX02, MediaType.NEC_525_HD,
|
||||
MediaType.ECMA_99_15, MediaType.NEC_8_SD, MediaType.RX03, MediaType.DOS_35_SS_DD_8,
|
||||
MediaType.DOS_35_SS_DD_9, MediaType.ACORN_525_SS_SD_80, MediaType.RX50, MediaType.ATARI_35_SS_DD_11,
|
||||
MediaType.ACORN_525_SS_DD_80, MediaType.ACORN_35_DS_DD, MediaType.DOS_35_DS_DD_8,
|
||||
MediaType.DOS_35_DS_DD_9, MediaType.ACORN_35_DS_HD, MediaType.DOS_525_HD, MediaType.ACORN_525_DS_DD,
|
||||
MediaType.DOS_35_HD, MediaType.XDF_525, MediaType.DMF, MediaType.XDF_35, MediaType.DOS_35_ED,
|
||||
MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_525_HD, MediaType.FDFORMAT_35_HD, MediaType.NEC_35_TD,
|
||||
MediaType.Unknown, MediaType.GENERIC_HDD, MediaType.FlashDrive, MediaType.CompactFlash,
|
||||
MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII,
|
||||
MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".fdi", ".hdi"};
|
||||
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize == 0)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors * sectorSize > int.MaxValue || sectors > (long)int.MaxValue * 8 * 33)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
fdihdr = new Anex86Header {hdrSize = 4096, dskSize = (int)(sectors * sectorSize), bps = (int)sectorSize};
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != imageInfo.SectorSize)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(4096 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(4096 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if((imageInfo.MediaType == MediaType.Unknown || imageInfo.MediaType == MediaType.GENERIC_HDD ||
|
||||
imageInfo.MediaType == MediaType.FlashDrive || imageInfo.MediaType == MediaType.CompactFlash ||
|
||||
imageInfo.MediaType == MediaType.CompactFlashType2 || imageInfo.MediaType == MediaType.PCCardTypeI ||
|
||||
imageInfo.MediaType == MediaType.PCCardTypeII || imageInfo.MediaType == MediaType.PCCardTypeIII ||
|
||||
imageInfo.MediaType == MediaType.PCCardTypeIV) && fdihdr.cylinders == 0)
|
||||
{
|
||||
fdihdr.cylinders = (int)(imageInfo.Sectors / 8 / 33);
|
||||
fdihdr.heads = 8;
|
||||
fdihdr.spt = 33;
|
||||
|
||||
while(fdihdr.cylinders == 0)
|
||||
{
|
||||
fdihdr.heads--;
|
||||
|
||||
if(fdihdr.heads == 0)
|
||||
{
|
||||
fdihdr.spt--;
|
||||
fdihdr.heads = 8;
|
||||
}
|
||||
|
||||
fdihdr.cylinders = (int)imageInfo.Sectors / fdihdr.heads / fdihdr.spt;
|
||||
|
||||
if(fdihdr.cylinders == 0 && fdihdr.heads == 0 && fdihdr.spt == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(fdihdr)];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fdihdr));
|
||||
Marshal.StructureToPtr(fdihdr, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
if(cylinders > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many cylinders.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(heads > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many heads.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorsPerTrack > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors per track.";
|
||||
return false;
|
||||
}
|
||||
|
||||
fdihdr.spt = (int)sectorsPerTrack;
|
||||
fdihdr.heads = (int)heads;
|
||||
fdihdr.cylinders = (int)cylinders;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Anex86Header
|
||||
{
|
||||
public int unknown;
|
||||
public int hddtype;
|
||||
public int hdrSize;
|
||||
public int dskSize;
|
||||
public int bps;
|
||||
public int spt;
|
||||
public int heads;
|
||||
public int cylinders;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
DiscImageChef.DiscImages/Anex86/Anex86.cs
Normal file
75
DiscImageChef.DiscImages/Anex86/Anex86.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Anex86.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86 : IWritableImage
|
||||
{
|
||||
IFilter anexImageFilter;
|
||||
Anex86Header fdihdr;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Anex86()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
71
DiscImageChef.DiscImages/Anex86/Identify.cs
Normal file
71
DiscImageChef.DiscImages/Anex86/Identify.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
fdihdr = new Anex86Header();
|
||||
|
||||
if(stream.Length < Marshal.SizeOf(fdihdr)) return false;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf(fdihdr)];
|
||||
stream.Read(hdrB, 0, hdrB.Length);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hdrB, GCHandleType.Pinned);
|
||||
fdihdr = (Anex86Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Anex86Header));
|
||||
handle.Free();
|
||||
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.unknown = {0}", fdihdr.unknown);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.hddtype = {0}", fdihdr.hddtype);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.hdrSize = {0}", fdihdr.hdrSize);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.dskSize = {0}", fdihdr.dskSize);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.bps = {0}", fdihdr.bps);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.spt = {0}", fdihdr.spt);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.heads = {0}", fdihdr.heads);
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "fdihdr.cylinders = {0}", fdihdr.cylinders);
|
||||
|
||||
return stream.Length == fdihdr.hdrSize + fdihdr.dskSize &&
|
||||
fdihdr.dskSize == fdihdr.bps * fdihdr.spt * fdihdr.heads * fdihdr.cylinders;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
DiscImageChef.DiscImages/Anex86/Properties.cs
Normal file
90
DiscImageChef.DiscImages/Anex86/Properties.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Anex86 Disk Image";
|
||||
public Guid Id => new Guid("0410003E-6E7B-40E6-9328-BA5651ADF6B7");
|
||||
|
||||
public string Format => "Anex86 disk image";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
// TODO: Test with real hardware to see real supported media
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.IBM23FD, MediaType.ECMA_66, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9,
|
||||
MediaType.ACORN_525_SS_SD_40, MediaType.ACORN_525_SS_DD_40, MediaType.ATARI_525_SD,
|
||||
MediaType.ATARI_525_DD, MediaType.ATARI_525_ED, MediaType.DOS_525_DS_DD_8, MediaType.DOS_525_DS_DD_9,
|
||||
MediaType.ECMA_70, MediaType.Apricot_35, MediaType.RX01, MediaType.RX02, MediaType.NEC_525_HD,
|
||||
MediaType.ECMA_99_15, MediaType.NEC_8_SD, MediaType.RX03, MediaType.DOS_35_SS_DD_8,
|
||||
MediaType.DOS_35_SS_DD_9, MediaType.ACORN_525_SS_SD_80, MediaType.RX50, MediaType.ATARI_35_SS_DD_11,
|
||||
MediaType.ACORN_525_SS_DD_80, MediaType.ACORN_35_DS_DD, MediaType.DOS_35_DS_DD_8,
|
||||
MediaType.DOS_35_DS_DD_9, MediaType.ACORN_35_DS_HD, MediaType.DOS_525_HD, MediaType.ACORN_525_DS_DD,
|
||||
MediaType.DOS_35_HD, MediaType.XDF_525, MediaType.DMF, MediaType.XDF_35, MediaType.DOS_35_ED,
|
||||
MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_525_HD, MediaType.FDFORMAT_35_HD, MediaType.NEC_35_TD,
|
||||
MediaType.Unknown, MediaType.GENERIC_HDD, MediaType.FlashDrive, MediaType.CompactFlash,
|
||||
MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII,
|
||||
MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".fdi", ".hdi"};
|
||||
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
129
DiscImageChef.DiscImages/Anex86/Read.cs
Normal file
129
DiscImageChef.DiscImages/Anex86/Read.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Reads Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86
|
||||
{
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
fdihdr = new Anex86Header();
|
||||
|
||||
if(stream.Length < Marshal.SizeOf(fdihdr)) return false;
|
||||
|
||||
byte[] hdrB = new byte[Marshal.SizeOf(fdihdr)];
|
||||
stream.Read(hdrB, 0, hdrB.Length);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hdrB, GCHandleType.Pinned);
|
||||
fdihdr = (Anex86Header)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Anex86Header));
|
||||
handle.Free();
|
||||
|
||||
imageInfo.MediaType = Geometry.GetMediaType(((ushort)fdihdr.cylinders, (byte)fdihdr.heads,
|
||||
(ushort)fdihdr.spt, (uint)fdihdr.bps, MediaEncoding.MFM,
|
||||
false));
|
||||
if(imageInfo.MediaType == MediaType.Unknown) imageInfo.MediaType = MediaType.GENERIC_HDD;
|
||||
|
||||
DicConsole.DebugWriteLine("Anex86 plugin", "MediaType: {0}", imageInfo.MediaType);
|
||||
|
||||
imageInfo.ImageSize = (ulong)fdihdr.dskSize;
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = (ulong)(fdihdr.cylinders * fdihdr.heads * fdihdr.spt);
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
imageInfo.SectorSize = (uint)fdihdr.bps;
|
||||
imageInfo.Cylinders = (uint)fdihdr.cylinders;
|
||||
imageInfo.Heads = (uint)fdihdr.heads;
|
||||
imageInfo.SectorsPerTrack = (uint)fdihdr.spt;
|
||||
|
||||
anexImageFilter = imageFilter;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
Stream stream = anexImageFilter.GetDataForkStream();
|
||||
|
||||
stream.Seek((long)((ulong)fdihdr.hdrSize + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
|
||||
stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
DiscImageChef.DiscImages/Anex86/Structs.cs
Normal file
52
DiscImageChef.DiscImages/Anex86/Structs.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Anex86Header
|
||||
{
|
||||
public int unknown;
|
||||
public int hddtype;
|
||||
public int hdrSize;
|
||||
public int dskSize;
|
||||
public int bps;
|
||||
public int spt;
|
||||
public int heads;
|
||||
public int cylinders;
|
||||
}
|
||||
}
|
||||
}
|
||||
119
DiscImageChef.DiscImages/Anex86/Unsupported.cs
Normal file
119
DiscImageChef.DiscImages/Anex86/Unsupported.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86 : IWritableImage
|
||||
{
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
}
|
||||
}
|
||||
269
DiscImageChef.DiscImages/Anex86/Write.cs
Normal file
269
DiscImageChef.DiscImages/Anex86/Write.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes Anex86 disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Anex86
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize == 0)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors * sectorSize > int.MaxValue || sectors > (long)int.MaxValue * 8 * 33)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
fdihdr = new Anex86Header {hdrSize = 4096, dskSize = (int)(sectors * sectorSize), bps = (int)sectorSize};
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != imageInfo.SectorSize)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(4096 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(4096 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if((imageInfo.MediaType == MediaType.Unknown || imageInfo.MediaType == MediaType.GENERIC_HDD ||
|
||||
imageInfo.MediaType == MediaType.FlashDrive || imageInfo.MediaType == MediaType.CompactFlash ||
|
||||
imageInfo.MediaType == MediaType.CompactFlashType2 || imageInfo.MediaType == MediaType.PCCardTypeI ||
|
||||
imageInfo.MediaType == MediaType.PCCardTypeII || imageInfo.MediaType == MediaType.PCCardTypeIII ||
|
||||
imageInfo.MediaType == MediaType.PCCardTypeIV) && fdihdr.cylinders == 0)
|
||||
{
|
||||
fdihdr.cylinders = (int)(imageInfo.Sectors / 8 / 33);
|
||||
fdihdr.heads = 8;
|
||||
fdihdr.spt = 33;
|
||||
|
||||
while(fdihdr.cylinders == 0)
|
||||
{
|
||||
fdihdr.heads--;
|
||||
|
||||
if(fdihdr.heads == 0)
|
||||
{
|
||||
fdihdr.spt--;
|
||||
fdihdr.heads = 8;
|
||||
}
|
||||
|
||||
fdihdr.cylinders = (int)imageInfo.Sectors / fdihdr.heads / fdihdr.spt;
|
||||
|
||||
if(fdihdr.cylinders == 0 && fdihdr.heads == 0 && fdihdr.spt == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(fdihdr)];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(fdihdr));
|
||||
Marshal.StructureToPtr(fdihdr, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
if(cylinders > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many cylinders.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(heads > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many heads.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorsPerTrack > int.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors per track.";
|
||||
return false;
|
||||
}
|
||||
|
||||
fdihdr.spt = (int)sectorsPerTrack;
|
||||
fdihdr.heads = (int)heads;
|
||||
fdihdr.cylinders = (int)cylinders;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,852 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Apple2MG.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Filters;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public class Apple2Mg : IWritableImage
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number, "2IMG"
|
||||
/// </summary>
|
||||
const uint MAGIC = 0x474D4932;
|
||||
/// <summary>
|
||||
/// Disk image created by ASIMOV2, "!nfc"
|
||||
/// </summary>
|
||||
const uint CREATOR_ASIMOV = 0x63666E21;
|
||||
/// <summary>
|
||||
/// Disk image created by Bernie ][ the Rescue, "B2TR"
|
||||
/// </summary>
|
||||
const uint CREATOR_BERNIE = 0x52543242;
|
||||
/// <summary>
|
||||
/// Disk image created by Catakig, "CTKG"
|
||||
/// </summary>
|
||||
const uint CREATOR_CATAKIG = 0x474B5443;
|
||||
/// <summary>
|
||||
/// Disk image created by Sheppy's ImageMaker, "ShIm"
|
||||
/// </summary>
|
||||
const uint CREATOR_SHEPPY = 0x6D496853;
|
||||
/// <summary>
|
||||
/// Disk image created by Sweet16, "WOOF"
|
||||
/// </summary>
|
||||
const uint CREATOR_SWEET = 0x464F4F57;
|
||||
/// <summary>
|
||||
/// Disk image created by XGS, "XGS!"
|
||||
/// </summary>
|
||||
const uint CREATOR_XGS = 0x21534758;
|
||||
/// <summary>
|
||||
/// Disk image created by CiderPress, "CdrP"
|
||||
/// </summary>
|
||||
const uint CREATOR_CIDER = 0x50726443;
|
||||
/// <summary>
|
||||
/// Disk image created by DiscImageChef, "dic "
|
||||
/// </summary>
|
||||
const uint CREATOR_DIC = 0x20636964;
|
||||
|
||||
const uint LOCKED_DISK = 0x80000000;
|
||||
const uint VALID_VOLUME_NUMBER = 0x00000100;
|
||||
const uint VOLUME_NUMBER_MASK = 0x000000FF;
|
||||
readonly int[] deinterleave = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
readonly int[] interleave = {0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15};
|
||||
|
||||
IFilter a2MgImageFilter;
|
||||
byte[] decodedImage;
|
||||
A2ImgHeader imageHeader;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Apple2Mg()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple 2IMG";
|
||||
public Guid Id => new Guid("CBAF8824-BA5F-415F-953A-19A03519B2D1");
|
||||
|
||||
public string Format => "Apple 2IMG";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 65) return false;
|
||||
|
||||
byte[] header = new byte[64];
|
||||
stream.Read(header, 0, 64);
|
||||
|
||||
uint magic = BitConverter.ToUInt32(header, 0x00);
|
||||
if(magic != MAGIC) return false;
|
||||
|
||||
uint dataoff = BitConverter.ToUInt32(header, 0x18);
|
||||
if(dataoff > stream.Length) return false;
|
||||
|
||||
uint datasize = BitConverter.ToUInt32(header, 0x1C);
|
||||
// There seems to be incorrect endian in some images on the wild
|
||||
if(datasize == 0x00800C00) datasize = 0x000C8000;
|
||||
if(dataoff + datasize > stream.Length) return false;
|
||||
|
||||
uint commentoff = BitConverter.ToUInt32(header, 0x20);
|
||||
if(commentoff > stream.Length) return false;
|
||||
|
||||
uint commentsize = BitConverter.ToUInt32(header, 0x24);
|
||||
if(commentoff + commentsize > stream.Length) return false;
|
||||
|
||||
uint creatoroff = BitConverter.ToUInt32(header, 0x28);
|
||||
if(creatoroff > stream.Length) return false;
|
||||
|
||||
uint creatorsize = BitConverter.ToUInt32(header, 0x2C);
|
||||
return creatoroff + creatorsize <= stream.Length;
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
imageHeader = new A2ImgHeader();
|
||||
|
||||
byte[] header = new byte[64];
|
||||
stream.Read(header, 0, 64);
|
||||
byte[] magic = new byte[4];
|
||||
byte[] creator = new byte[4];
|
||||
|
||||
Array.Copy(header, 0, magic, 0, 4);
|
||||
Array.Copy(header, 4, creator, 0, 4);
|
||||
|
||||
imageHeader.Magic = BitConverter.ToUInt32(header, 0x00);
|
||||
imageHeader.Creator = BitConverter.ToUInt32(header, 0x04);
|
||||
imageHeader.HeaderSize = BitConverter.ToUInt16(header, 0x08);
|
||||
imageHeader.Version = BitConverter.ToUInt16(header, 0x0A);
|
||||
imageHeader.ImageFormat = (SectorOrder)BitConverter.ToUInt32(header, 0x0C);
|
||||
imageHeader.Flags = BitConverter.ToUInt32(header, 0x10);
|
||||
imageHeader.Blocks = BitConverter.ToUInt32(header, 0x14);
|
||||
imageHeader.DataOffset = BitConverter.ToUInt32(header, 0x18);
|
||||
imageHeader.DataSize = BitConverter.ToUInt32(header, 0x1C);
|
||||
imageHeader.CommentOffset = BitConverter.ToUInt32(header, 0x20);
|
||||
imageHeader.CommentSize = BitConverter.ToUInt32(header, 0x24);
|
||||
imageHeader.CreatorSpecificOffset = BitConverter.ToUInt32(header, 0x28);
|
||||
imageHeader.CreatorSpecificSize = BitConverter.ToUInt32(header, 0x2C);
|
||||
imageHeader.Reserved1 = BitConverter.ToUInt32(header, 0x30);
|
||||
imageHeader.Reserved2 = BitConverter.ToUInt32(header, 0x34);
|
||||
imageHeader.Reserved3 = BitConverter.ToUInt32(header, 0x38);
|
||||
imageHeader.Reserved4 = BitConverter.ToUInt32(header, 0x3C);
|
||||
|
||||
if(imageHeader.DataSize == 0x00800C00)
|
||||
{
|
||||
imageHeader.DataSize = 0x000C8000;
|
||||
DicConsole.DebugWriteLine("2MG plugin", "Detected incorrect endian on data size field, correcting.");
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.magic = \"{0}\"",
|
||||
Encoding.ASCII.GetString(magic));
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creator = \"{0}\"",
|
||||
Encoding.ASCII.GetString(creator));
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.headerSize = {0}", imageHeader.HeaderSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.version = {0}", imageHeader.Version);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.imageFormat = {0}", imageHeader.ImageFormat);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.flags = 0x{0:X8}", imageHeader.Flags);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.blocks = {0}", imageHeader.Blocks);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataOffset = 0x{0:X8}", imageHeader.DataOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataSize = {0}", imageHeader.DataSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentOffset = 0x{0:X8}", imageHeader.CommentOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentSize = {0}", imageHeader.CommentSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificOffset = 0x{0:X8}",
|
||||
imageHeader.CreatorSpecificOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificSize = {0}",
|
||||
imageHeader.CreatorSpecificSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved1 = 0x{0:X8}", imageHeader.Reserved1);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved2 = 0x{0:X8}", imageHeader.Reserved2);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved3 = 0x{0:X8}", imageHeader.Reserved3);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved4 = 0x{0:X8}", imageHeader.Reserved4);
|
||||
|
||||
if(imageHeader.DataSize == 0 && imageHeader.Blocks == 0 &&
|
||||
imageHeader.ImageFormat != SectorOrder.ProDos) return false;
|
||||
|
||||
byte[] tmp;
|
||||
int[] offsets;
|
||||
|
||||
switch(imageHeader.ImageFormat)
|
||||
{
|
||||
case SectorOrder.Nibbles:
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
AppleNib nibPlugin = new AppleNib();
|
||||
ZZZNoFilter noFilter = new ZZZNoFilter();
|
||||
noFilter.Open(tmp);
|
||||
nibPlugin.Open(noFilter);
|
||||
decodedImage = nibPlugin.ReadSectors(0, (uint)nibPlugin.Info.Sectors);
|
||||
imageInfo.Sectors = nibPlugin.Info.Sectors;
|
||||
imageInfo.SectorSize = nibPlugin.Info.SectorSize;
|
||||
break;
|
||||
case SectorOrder.Dos when imageHeader.DataSize == 143360:
|
||||
case SectorOrder.ProDos when imageHeader.DataSize == 143360:
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
bool isDos = tmp[0x11001] == 17 && tmp[0x11002] < 16 && tmp[0x11027] <= 122 && tmp[0x11034] == 35 &&
|
||||
tmp[0x11035] == 16 && tmp[0x11036] == 0 && tmp[0x11037] == 1;
|
||||
decodedImage = new byte[imageHeader.DataSize];
|
||||
offsets = imageHeader.ImageFormat == SectorOrder.Dos
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, decodedImage, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.Sectors = 560;
|
||||
imageInfo.SectorSize = 256;
|
||||
break;
|
||||
case SectorOrder.Dos when imageHeader.DataSize == 819200:
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
decodedImage = new byte[imageHeader.DataSize];
|
||||
offsets = interleave;
|
||||
for(int t = 0; t < 200; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, decodedImage, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.Sectors = 1600;
|
||||
imageInfo.SectorSize = 512;
|
||||
break;
|
||||
default:
|
||||
decodedImage = null;
|
||||
imageInfo.SectorSize = 512;
|
||||
imageInfo.Sectors = imageHeader.DataSize / 512;
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.ImageSize = imageHeader.DataSize;
|
||||
|
||||
switch(imageHeader.Creator)
|
||||
{
|
||||
case CREATOR_ASIMOV:
|
||||
imageInfo.Application = "ASIMOV2";
|
||||
break;
|
||||
case CREATOR_BERNIE:
|
||||
imageInfo.Application = "Bernie ][ the Rescue";
|
||||
break;
|
||||
case CREATOR_CATAKIG:
|
||||
imageInfo.Application = "Catakig";
|
||||
break;
|
||||
case CREATOR_SHEPPY:
|
||||
imageInfo.Application = "Sheppy's ImageMaker";
|
||||
break;
|
||||
case CREATOR_SWEET:
|
||||
imageInfo.Application = "Sweet16";
|
||||
break;
|
||||
case CREATOR_XGS:
|
||||
imageInfo.Application = "XGS";
|
||||
break;
|
||||
case CREATOR_CIDER:
|
||||
imageInfo.Application = "CiderPress";
|
||||
break;
|
||||
case CREATOR_DIC:
|
||||
imageInfo.Application = "DiscImageChef";
|
||||
break;
|
||||
default:
|
||||
imageInfo.Application = $"Unknown creator code \"{Encoding.ASCII.GetString(creator)}\"";
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.Version = imageHeader.Version.ToString();
|
||||
|
||||
if(imageHeader.CommentOffset != 0 && imageHeader.CommentSize != 0)
|
||||
{
|
||||
stream.Seek(imageHeader.CommentOffset, SeekOrigin.Begin);
|
||||
|
||||
byte[] comments = new byte[imageHeader.CommentSize];
|
||||
stream.Read(comments, 0, (int)imageHeader.CommentSize);
|
||||
imageInfo.Comments = Encoding.ASCII.GetString(comments);
|
||||
}
|
||||
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.MediaType = GetMediaType();
|
||||
|
||||
a2MgImageFilter = imageFilter;
|
||||
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
DicConsole.VerboseWriteLine("2MG image contains a disk of type {0}", imageInfo.MediaType);
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
DicConsole.VerboseWriteLine("2MG comments: {0}", imageInfo.Comments);
|
||||
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
case MediaType.Apple32SS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 1;
|
||||
imageInfo.SectorsPerTrack = 13;
|
||||
break;
|
||||
case MediaType.Apple32DS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 13;
|
||||
break;
|
||||
case MediaType.Apple33SS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 1;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case MediaType.Apple33DS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case MediaType.AppleSonySS:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 1;
|
||||
// Variable sectors per track, this suffices
|
||||
imageInfo.SectorsPerTrack = 10;
|
||||
break;
|
||||
case MediaType.AppleSonyDS:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 2;
|
||||
// Variable sectors per track, this suffices
|
||||
imageInfo.SectorsPerTrack = 10;
|
||||
break;
|
||||
case MediaType.DOS_35_HD:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 18;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
if(decodedImage != null)
|
||||
Array.Copy(decodedImage, (long)(sectorAddress * imageInfo.SectorSize), buffer, 0,
|
||||
length * imageInfo.SectorSize);
|
||||
else
|
||||
{
|
||||
Stream stream = a2MgImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)(imageHeader.DataOffset + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.Apple32SS, MediaType.Apple33SS, MediaType.AppleSonySS, MediaType.AppleSonyDS,
|
||||
MediaType.DOS_35_HD, MediaType.Unknown, MediaType.GENERIC_HDD, MediaType.FlashDrive,
|
||||
MediaType.CompactFlash, MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII,
|
||||
MediaType.PCCardTypeIII, MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".2mg"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
if(sectorSize != 256 || mediaType != MediaType.Apple32SS && mediaType != MediaType.Apple33SS)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > uint.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != imageInfo.SectorSize)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(0x40 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(0x40 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(0x40 + 17 * 16 * 256, SeekOrigin.Begin);
|
||||
byte[] tmp = new byte[256];
|
||||
writingStream.Read(tmp, 0, tmp.Length);
|
||||
bool isDos = tmp[0x01] == 17 && tmp[0x02] < 16 && tmp[0x27] <= 122 && tmp[0x34] == 35 && tmp[0x35] == 16 &&
|
||||
tmp[0x36] == 0 && tmp[0x37] == 1;
|
||||
|
||||
imageHeader = new A2ImgHeader
|
||||
{
|
||||
Blocks = (uint)(imageInfo.Sectors * imageInfo.SectorSize) / 512,
|
||||
Creator = CREATOR_DIC,
|
||||
DataOffset = 0x40,
|
||||
DataSize = (uint)(imageInfo.Sectors * imageInfo.SectorSize),
|
||||
Flags =
|
||||
(uint)(imageInfo.LastMediaSequence != 0
|
||||
? VALID_VOLUME_NUMBER + (imageInfo.MediaSequence & 0xFF)
|
||||
: 0),
|
||||
HeaderSize = 0x40,
|
||||
ImageFormat = isDos ? SectorOrder.Dos : SectorOrder.ProDos,
|
||||
Magic = MAGIC,
|
||||
Version = 1
|
||||
};
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
{
|
||||
writingStream.Seek(0, SeekOrigin.End);
|
||||
tmp = Encoding.UTF8.GetBytes(imageInfo.Comments);
|
||||
imageHeader.CommentOffset = (uint)writingStream.Position;
|
||||
imageHeader.CommentSize = (uint)(tmp.Length + 1);
|
||||
writingStream.Write(tmp, 0, tmp.Length);
|
||||
writingStream.WriteByte(0);
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(typeof(A2ImgHeader))];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(A2ImgHeader)));
|
||||
Marshal.StructureToPtr(imageHeader, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
imageInfo.Comments = metadata.Comments;
|
||||
imageInfo.LastMediaSequence = metadata.LastMediaSequence;
|
||||
imageInfo.MediaSequence = metadata.MediaSequence;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
MediaType GetMediaType()
|
||||
{
|
||||
switch(imageInfo.Sectors)
|
||||
{
|
||||
case 455: return MediaType.Apple32SS;
|
||||
case 910: return MediaType.Apple32DS;
|
||||
case 560: return MediaType.Apple33SS;
|
||||
case 1120: return MediaType.Apple33DS;
|
||||
case 800: return MediaType.AppleSonySS;
|
||||
case 1600: return MediaType.AppleSonyDS;
|
||||
case 2880: return MediaType.DOS_35_HD;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
enum SectorOrder : uint
|
||||
{
|
||||
Dos = 0,
|
||||
ProDos = 1,
|
||||
Nibbles = 2
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct A2ImgHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, magic
|
||||
/// </summary>
|
||||
public uint Magic;
|
||||
/// <summary>
|
||||
/// Offset 0x04, disk image creator ID
|
||||
/// </summary>
|
||||
public uint Creator;
|
||||
/// <summary>
|
||||
/// Offset 0x08, header size, constant 0x0040
|
||||
/// </summary>
|
||||
public ushort HeaderSize;
|
||||
/// <summary>
|
||||
/// Offset 0x0A, disk image version
|
||||
/// </summary>
|
||||
public ushort Version;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, disk image format
|
||||
/// </summary>
|
||||
public SectorOrder ImageFormat;
|
||||
/// <summary>
|
||||
/// Offset 0x10, flags and volume number
|
||||
/// </summary>
|
||||
public uint Flags;
|
||||
/// <summary>
|
||||
/// Offset 0x14, blocks for ProDOS, 0 otherwise
|
||||
/// </summary>
|
||||
public uint Blocks;
|
||||
/// <summary>
|
||||
/// Offset 0x18, offset to data
|
||||
/// </summary>
|
||||
public uint DataOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x1C, data size in bytes
|
||||
/// </summary>
|
||||
public uint DataSize;
|
||||
/// <summary>
|
||||
/// Offset 0x20, offset to optional comment
|
||||
/// </summary>
|
||||
public uint CommentOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x24, length of optional comment
|
||||
/// </summary>
|
||||
public uint CommentSize;
|
||||
/// <summary>
|
||||
/// Offset 0x28, offset to creator specific chunk
|
||||
/// </summary>
|
||||
public uint CreatorSpecificOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x2C, creator specific chunk size
|
||||
/// </summary>
|
||||
public uint CreatorSpecificSize;
|
||||
/// <summary>
|
||||
/// Offset 0x30, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved1;
|
||||
/// <summary>
|
||||
/// Offset 0x34, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved2;
|
||||
/// <summary>
|
||||
/// Offset 0x38, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved3;
|
||||
/// <summary>
|
||||
/// Offset 0x3C, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved4;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
DiscImageChef.DiscImages/Apple2MG/Apple2MG.cs
Normal file
76
DiscImageChef.DiscImages/Apple2MG/Apple2MG.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Apple2MG.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg : IWritableImage
|
||||
{
|
||||
IFilter a2MgImageFilter;
|
||||
byte[] decodedImage;
|
||||
A2ImgHeader imageHeader;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Apple2Mg()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
80
DiscImageChef.DiscImages/Apple2MG/Constants.cs
Normal file
80
DiscImageChef.DiscImages/Apple2MG/Constants.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number, "2IMG"
|
||||
/// </summary>
|
||||
const uint MAGIC = 0x474D4932;
|
||||
/// <summary>
|
||||
/// Disk image created by ASIMOV2, "!nfc"
|
||||
/// </summary>
|
||||
const uint CREATOR_ASIMOV = 0x63666E21;
|
||||
/// <summary>
|
||||
/// Disk image created by Bernie ][ the Rescue, "B2TR"
|
||||
/// </summary>
|
||||
const uint CREATOR_BERNIE = 0x52543242;
|
||||
/// <summary>
|
||||
/// Disk image created by Catakig, "CTKG"
|
||||
/// </summary>
|
||||
const uint CREATOR_CATAKIG = 0x474B5443;
|
||||
/// <summary>
|
||||
/// Disk image created by Sheppy's ImageMaker, "ShIm"
|
||||
/// </summary>
|
||||
const uint CREATOR_SHEPPY = 0x6D496853;
|
||||
/// <summary>
|
||||
/// Disk image created by Sweet16, "WOOF"
|
||||
/// </summary>
|
||||
const uint CREATOR_SWEET = 0x464F4F57;
|
||||
/// <summary>
|
||||
/// Disk image created by XGS, "XGS!"
|
||||
/// </summary>
|
||||
const uint CREATOR_XGS = 0x21534758;
|
||||
/// <summary>
|
||||
/// Disk image created by CiderPress, "CdrP"
|
||||
/// </summary>
|
||||
const uint CREATOR_CIDER = 0x50726443;
|
||||
/// <summary>
|
||||
/// Disk image created by DiscImageChef, "dic "
|
||||
/// </summary>
|
||||
const uint CREATOR_DIC = 0x20636964;
|
||||
|
||||
const uint LOCKED_DISK = 0x80000000;
|
||||
const uint VALID_VOLUME_NUMBER = 0x00000100;
|
||||
const uint VOLUME_NUMBER_MASK = 0x000000FF;
|
||||
readonly int[] deinterleave = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
readonly int[] interleave = {0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15};
|
||||
}
|
||||
}
|
||||
44
DiscImageChef.DiscImages/Apple2MG/Enums.cs
Normal file
44
DiscImageChef.DiscImages/Apple2MG/Enums.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
enum SectorOrder : uint
|
||||
{
|
||||
Dos = 0,
|
||||
ProDos = 1,
|
||||
Nibbles = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
54
DiscImageChef.DiscImages/Apple2MG/Helpers.cs
Normal file
54
DiscImageChef.DiscImages/Apple2MG/Helpers.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
MediaType GetMediaType()
|
||||
{
|
||||
switch(imageInfo.Sectors)
|
||||
{
|
||||
case 455: return MediaType.Apple32SS;
|
||||
case 910: return MediaType.Apple32DS;
|
||||
case 560: return MediaType.Apple33SS;
|
||||
case 1120: return MediaType.Apple33DS;
|
||||
case 800: return MediaType.AppleSonySS;
|
||||
case 1600: return MediaType.AppleSonyDS;
|
||||
case 2880: return MediaType.DOS_35_HD;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
DiscImageChef.DiscImages/Apple2MG/Identify.cs
Normal file
75
DiscImageChef.DiscImages/Apple2MG/Identify.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 65) return false;
|
||||
|
||||
byte[] header = new byte[64];
|
||||
stream.Read(header, 0, 64);
|
||||
|
||||
uint magic = BitConverter.ToUInt32(header, 0x00);
|
||||
if(magic != MAGIC) return false;
|
||||
|
||||
uint dataoff = BitConverter.ToUInt32(header, 0x18);
|
||||
if(dataoff > stream.Length) return false;
|
||||
|
||||
uint datasize = BitConverter.ToUInt32(header, 0x1C);
|
||||
// There seems to be incorrect endian in some images on the wild
|
||||
if(datasize == 0x00800C00) datasize = 0x000C8000;
|
||||
if(dataoff + datasize > stream.Length) return false;
|
||||
|
||||
uint commentoff = BitConverter.ToUInt32(header, 0x20);
|
||||
if(commentoff > stream.Length) return false;
|
||||
|
||||
uint commentsize = BitConverter.ToUInt32(header, 0x24);
|
||||
if(commentoff + commentsize > stream.Length) return false;
|
||||
|
||||
uint creatoroff = BitConverter.ToUInt32(header, 0x28);
|
||||
if(creatoroff > stream.Length) return false;
|
||||
|
||||
uint creatorsize = BitConverter.ToUInt32(header, 0x2C);
|
||||
return creatoroff + creatorsize <= stream.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
DiscImageChef.DiscImages/Apple2MG/Properties.cs
Normal file
80
DiscImageChef.DiscImages/Apple2MG/Properties.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple 2IMG";
|
||||
public Guid Id => new Guid("CBAF8824-BA5F-415F-953A-19A03519B2D1");
|
||||
|
||||
public string Format => "Apple 2IMG";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.Apple32SS, MediaType.Apple33SS, MediaType.AppleSonySS, MediaType.AppleSonyDS,
|
||||
MediaType.DOS_35_HD, MediaType.Unknown, MediaType.GENERIC_HDD, MediaType.FlashDrive,
|
||||
MediaType.CompactFlash, MediaType.CompactFlashType2, MediaType.PCCardTypeI, MediaType.PCCardTypeII,
|
||||
MediaType.PCCardTypeIII, MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".2mg"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
298
DiscImageChef.DiscImages/Apple2MG/Read.cs
Normal file
298
DiscImageChef.DiscImages/Apple2MG/Read.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Reads XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Filters;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
imageHeader = new A2ImgHeader();
|
||||
|
||||
byte[] header = new byte[64];
|
||||
stream.Read(header, 0, 64);
|
||||
byte[] magic = new byte[4];
|
||||
byte[] creator = new byte[4];
|
||||
|
||||
Array.Copy(header, 0, magic, 0, 4);
|
||||
Array.Copy(header, 4, creator, 0, 4);
|
||||
|
||||
imageHeader.Magic = BitConverter.ToUInt32(header, 0x00);
|
||||
imageHeader.Creator = BitConverter.ToUInt32(header, 0x04);
|
||||
imageHeader.HeaderSize = BitConverter.ToUInt16(header, 0x08);
|
||||
imageHeader.Version = BitConverter.ToUInt16(header, 0x0A);
|
||||
imageHeader.ImageFormat = (SectorOrder)BitConverter.ToUInt32(header, 0x0C);
|
||||
imageHeader.Flags = BitConverter.ToUInt32(header, 0x10);
|
||||
imageHeader.Blocks = BitConverter.ToUInt32(header, 0x14);
|
||||
imageHeader.DataOffset = BitConverter.ToUInt32(header, 0x18);
|
||||
imageHeader.DataSize = BitConverter.ToUInt32(header, 0x1C);
|
||||
imageHeader.CommentOffset = BitConverter.ToUInt32(header, 0x20);
|
||||
imageHeader.CommentSize = BitConverter.ToUInt32(header, 0x24);
|
||||
imageHeader.CreatorSpecificOffset = BitConverter.ToUInt32(header, 0x28);
|
||||
imageHeader.CreatorSpecificSize = BitConverter.ToUInt32(header, 0x2C);
|
||||
imageHeader.Reserved1 = BitConverter.ToUInt32(header, 0x30);
|
||||
imageHeader.Reserved2 = BitConverter.ToUInt32(header, 0x34);
|
||||
imageHeader.Reserved3 = BitConverter.ToUInt32(header, 0x38);
|
||||
imageHeader.Reserved4 = BitConverter.ToUInt32(header, 0x3C);
|
||||
|
||||
if(imageHeader.DataSize == 0x00800C00)
|
||||
{
|
||||
imageHeader.DataSize = 0x000C8000;
|
||||
DicConsole.DebugWriteLine("2MG plugin", "Detected incorrect endian on data size field, correcting.");
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.magic = \"{0}\"",
|
||||
Encoding.ASCII.GetString(magic));
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creator = \"{0}\"",
|
||||
Encoding.ASCII.GetString(creator));
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.headerSize = {0}", imageHeader.HeaderSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.version = {0}", imageHeader.Version);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.imageFormat = {0}", imageHeader.ImageFormat);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.flags = 0x{0:X8}", imageHeader.Flags);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.blocks = {0}", imageHeader.Blocks);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataOffset = 0x{0:X8}", imageHeader.DataOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.dataSize = {0}", imageHeader.DataSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentOffset = 0x{0:X8}", imageHeader.CommentOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.commentSize = {0}", imageHeader.CommentSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificOffset = 0x{0:X8}",
|
||||
imageHeader.CreatorSpecificOffset);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.creatorSpecificSize = {0}",
|
||||
imageHeader.CreatorSpecificSize);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved1 = 0x{0:X8}", imageHeader.Reserved1);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved2 = 0x{0:X8}", imageHeader.Reserved2);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved3 = 0x{0:X8}", imageHeader.Reserved3);
|
||||
DicConsole.DebugWriteLine("2MG plugin", "ImageHeader.reserved4 = 0x{0:X8}", imageHeader.Reserved4);
|
||||
|
||||
if(imageHeader.DataSize == 0 && imageHeader.Blocks == 0 &&
|
||||
imageHeader.ImageFormat != SectorOrder.ProDos) return false;
|
||||
|
||||
byte[] tmp;
|
||||
int[] offsets;
|
||||
|
||||
switch(imageHeader.ImageFormat)
|
||||
{
|
||||
case SectorOrder.Nibbles:
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
AppleNib nibPlugin = new AppleNib();
|
||||
ZZZNoFilter noFilter = new ZZZNoFilter();
|
||||
noFilter.Open(tmp);
|
||||
nibPlugin.Open(noFilter);
|
||||
decodedImage = nibPlugin.ReadSectors(0, (uint)nibPlugin.Info.Sectors);
|
||||
imageInfo.Sectors = nibPlugin.Info.Sectors;
|
||||
imageInfo.SectorSize = nibPlugin.Info.SectorSize;
|
||||
break;
|
||||
case SectorOrder.Dos when imageHeader.DataSize == 143360:
|
||||
case SectorOrder.ProDos when imageHeader.DataSize == 143360:
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
bool isDos = tmp[0x11001] == 17 && tmp[0x11002] < 16 && tmp[0x11027] <= 122 && tmp[0x11034] == 35 &&
|
||||
tmp[0x11035] == 16 && tmp[0x11036] == 0 && tmp[0x11037] == 1;
|
||||
decodedImage = new byte[imageHeader.DataSize];
|
||||
offsets = imageHeader.ImageFormat == SectorOrder.Dos
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, decodedImage, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.Sectors = 560;
|
||||
imageInfo.SectorSize = 256;
|
||||
break;
|
||||
case SectorOrder.Dos when imageHeader.DataSize == 819200:
|
||||
stream.Seek(imageHeader.DataOffset, SeekOrigin.Begin);
|
||||
tmp = new byte[imageHeader.DataSize];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
decodedImage = new byte[imageHeader.DataSize];
|
||||
offsets = interleave;
|
||||
for(int t = 0; t < 200; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, decodedImage, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.Sectors = 1600;
|
||||
imageInfo.SectorSize = 512;
|
||||
break;
|
||||
default:
|
||||
decodedImage = null;
|
||||
imageInfo.SectorSize = 512;
|
||||
imageInfo.Sectors = imageHeader.DataSize / 512;
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.ImageSize = imageHeader.DataSize;
|
||||
|
||||
switch(imageHeader.Creator)
|
||||
{
|
||||
case CREATOR_ASIMOV:
|
||||
imageInfo.Application = "ASIMOV2";
|
||||
break;
|
||||
case CREATOR_BERNIE:
|
||||
imageInfo.Application = "Bernie ][ the Rescue";
|
||||
break;
|
||||
case CREATOR_CATAKIG:
|
||||
imageInfo.Application = "Catakig";
|
||||
break;
|
||||
case CREATOR_SHEPPY:
|
||||
imageInfo.Application = "Sheppy's ImageMaker";
|
||||
break;
|
||||
case CREATOR_SWEET:
|
||||
imageInfo.Application = "Sweet16";
|
||||
break;
|
||||
case CREATOR_XGS:
|
||||
imageInfo.Application = "XGS";
|
||||
break;
|
||||
case CREATOR_CIDER:
|
||||
imageInfo.Application = "CiderPress";
|
||||
break;
|
||||
case CREATOR_DIC:
|
||||
imageInfo.Application = "DiscImageChef";
|
||||
break;
|
||||
default:
|
||||
imageInfo.Application = $"Unknown creator code \"{Encoding.ASCII.GetString(creator)}\"";
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.Version = imageHeader.Version.ToString();
|
||||
|
||||
if(imageHeader.CommentOffset != 0 && imageHeader.CommentSize != 0)
|
||||
{
|
||||
stream.Seek(imageHeader.CommentOffset, SeekOrigin.Begin);
|
||||
|
||||
byte[] comments = new byte[imageHeader.CommentSize];
|
||||
stream.Read(comments, 0, (int)imageHeader.CommentSize);
|
||||
imageInfo.Comments = Encoding.ASCII.GetString(comments);
|
||||
}
|
||||
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.MediaType = GetMediaType();
|
||||
|
||||
a2MgImageFilter = imageFilter;
|
||||
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
DicConsole.VerboseWriteLine("2MG image contains a disk of type {0}", imageInfo.MediaType);
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
DicConsole.VerboseWriteLine("2MG comments: {0}", imageInfo.Comments);
|
||||
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
case MediaType.Apple32SS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 1;
|
||||
imageInfo.SectorsPerTrack = 13;
|
||||
break;
|
||||
case MediaType.Apple32DS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 13;
|
||||
break;
|
||||
case MediaType.Apple33SS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 1;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case MediaType.Apple33DS:
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case MediaType.AppleSonySS:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 1;
|
||||
// Variable sectors per track, this suffices
|
||||
imageInfo.SectorsPerTrack = 10;
|
||||
break;
|
||||
case MediaType.AppleSonyDS:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 2;
|
||||
// Variable sectors per track, this suffices
|
||||
imageInfo.SectorsPerTrack = 10;
|
||||
break;
|
||||
case MediaType.DOS_35_HD:
|
||||
imageInfo.Cylinders = 80;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 18;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
if(decodedImage != null)
|
||||
Array.Copy(decodedImage, (long)(sectorAddress * imageInfo.SectorSize), buffer, 0,
|
||||
length * imageInfo.SectorSize);
|
||||
else
|
||||
{
|
||||
Stream stream = a2MgImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)(imageHeader.DataOffset + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
stream.Read(buffer, 0, (int)(length * imageInfo.SectorSize));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
DiscImageChef.DiscImages/Apple2MG/Structs.cs
Normal file
114
DiscImageChef.DiscImages/Apple2MG/Structs.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct A2ImgHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, magic
|
||||
/// </summary>
|
||||
public uint Magic;
|
||||
/// <summary>
|
||||
/// Offset 0x04, disk image creator ID
|
||||
/// </summary>
|
||||
public uint Creator;
|
||||
/// <summary>
|
||||
/// Offset 0x08, header size, constant 0x0040
|
||||
/// </summary>
|
||||
public ushort HeaderSize;
|
||||
/// <summary>
|
||||
/// Offset 0x0A, disk image version
|
||||
/// </summary>
|
||||
public ushort Version;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, disk image format
|
||||
/// </summary>
|
||||
public SectorOrder ImageFormat;
|
||||
/// <summary>
|
||||
/// Offset 0x10, flags and volume number
|
||||
/// </summary>
|
||||
public uint Flags;
|
||||
/// <summary>
|
||||
/// Offset 0x14, blocks for ProDOS, 0 otherwise
|
||||
/// </summary>
|
||||
public uint Blocks;
|
||||
/// <summary>
|
||||
/// Offset 0x18, offset to data
|
||||
/// </summary>
|
||||
public uint DataOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x1C, data size in bytes
|
||||
/// </summary>
|
||||
public uint DataSize;
|
||||
/// <summary>
|
||||
/// Offset 0x20, offset to optional comment
|
||||
/// </summary>
|
||||
public uint CommentOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x24, length of optional comment
|
||||
/// </summary>
|
||||
public uint CommentSize;
|
||||
/// <summary>
|
||||
/// Offset 0x28, offset to creator specific chunk
|
||||
/// </summary>
|
||||
public uint CreatorSpecificOffset;
|
||||
/// <summary>
|
||||
/// Offset 0x2C, creator specific chunk size
|
||||
/// </summary>
|
||||
public uint CreatorSpecificSize;
|
||||
/// <summary>
|
||||
/// Offset 0x30, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved1;
|
||||
/// <summary>
|
||||
/// Offset 0x34, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved2;
|
||||
/// <summary>
|
||||
/// Offset 0x38, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved3;
|
||||
/// <summary>
|
||||
/// Offset 0x3C, reserved, should be zero
|
||||
/// </summary>
|
||||
public uint Reserved4;
|
||||
}
|
||||
}
|
||||
}
|
||||
138
DiscImageChef.DiscImages/Apple2MG/Unsupported.cs
Normal file
138
DiscImageChef.DiscImages/Apple2MG/Unsupported.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
257
DiscImageChef.DiscImages/Apple2MG/Write.cs
Normal file
257
DiscImageChef.DiscImages/Apple2MG/Write.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes XGS emulator disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apple2Mg
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
if(sectorSize != 256 || mediaType != MediaType.Apple32SS && mediaType != MediaType.Apple33SS)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > uint.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != imageInfo.SectorSize)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(0x40 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek((long)(0x40 + sectorAddress * imageInfo.SectorSize), SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(0x40 + 17 * 16 * 256, SeekOrigin.Begin);
|
||||
byte[] tmp = new byte[256];
|
||||
writingStream.Read(tmp, 0, tmp.Length);
|
||||
bool isDos = tmp[0x01] == 17 && tmp[0x02] < 16 && tmp[0x27] <= 122 && tmp[0x34] == 35 && tmp[0x35] == 16 &&
|
||||
tmp[0x36] == 0 && tmp[0x37] == 1;
|
||||
|
||||
imageHeader = new A2ImgHeader
|
||||
{
|
||||
Blocks = (uint)(imageInfo.Sectors * imageInfo.SectorSize) / 512,
|
||||
Creator = CREATOR_DIC,
|
||||
DataOffset = 0x40,
|
||||
DataSize = (uint)(imageInfo.Sectors * imageInfo.SectorSize),
|
||||
Flags =
|
||||
(uint)(imageInfo.LastMediaSequence != 0
|
||||
? VALID_VOLUME_NUMBER + (imageInfo.MediaSequence & 0xFF)
|
||||
: 0),
|
||||
HeaderSize = 0x40,
|
||||
ImageFormat = isDos ? SectorOrder.Dos : SectorOrder.ProDos,
|
||||
Magic = MAGIC,
|
||||
Version = 1
|
||||
};
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
{
|
||||
writingStream.Seek(0, SeekOrigin.End);
|
||||
tmp = Encoding.UTF8.GetBytes(imageInfo.Comments);
|
||||
imageHeader.CommentOffset = (uint)writingStream.Position;
|
||||
imageHeader.CommentSize = (uint)(tmp.Length + 1);
|
||||
writingStream.Write(tmp, 0, tmp.Length);
|
||||
writingStream.WriteByte(0);
|
||||
}
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(typeof(A2ImgHeader))];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(A2ImgHeader)));
|
||||
Marshal.StructureToPtr(imageHeader, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
imageInfo.Comments = metadata.Comments;
|
||||
imageInfo.LastMediaSequence = metadata.LastMediaSequence;
|
||||
imageInfo.MediaSequence = metadata.MediaSequence;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : AppleDOS.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public class AppleDos : IWritableImage
|
||||
{
|
||||
readonly int[] deinterleave = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
readonly int[] interleave = {0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15};
|
||||
|
||||
byte[] deinterleaved;
|
||||
string extension;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public AppleDos()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple ][ Interleaved Disk Image";
|
||||
public Guid Id => new Guid("A5828AC0-62C9-4304-81D4-EFD4AAE47360");
|
||||
|
||||
public string Format =>
|
||||
extension == ".po"
|
||||
? "Apple ][ Interleaved Disk Image (ProDOS order)"
|
||||
: "Apple ][ Interleaved Disk Image (DOS order)";
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower();
|
||||
|
||||
return imageFilter.GetDataForkLength() == 143360 && (extension == ".po" || extension == ".do");
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
byte[] tmp = new byte[imageFilter.GetDataForkLength()];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
|
||||
bool isDos = tmp[0x11001] == 17 && tmp[0x11002] < 16 && tmp[0x11027] <= 122 && tmp[0x11034] == 35 &&
|
||||
tmp[0x11035] == 16 && tmp[0x11036] == 0 && tmp[0x11037] == 1;
|
||||
|
||||
deinterleaved = new byte[tmp.Length];
|
||||
|
||||
extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower();
|
||||
|
||||
int[] offsets = extension == ".do"
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, deinterleaved, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.SectorSize = 256;
|
||||
imageInfo.ImageSize = (ulong)imageFilter.GetDataForkLength();
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = 560;
|
||||
imageInfo.MediaType = MediaType.Apple33SS;
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
Array.Copy(deinterleaved, (int)(sectorAddress * imageInfo.SectorSize), buffer, 0, buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] {MediaType.Apple33SS};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".do", ".po"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 256)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mediaType != MediaType.Apple33SS)
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > uint.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
deinterleaved = new byte[35 * 16 * 256];
|
||||
extension = Path.GetExtension(path);
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
return WriteSectors(data, sectorAddress, 1);
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
Array.Copy(data, 0, deinterleaved, (int)(sectorAddress * imageInfo.SectorSize), data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDos = deinterleaved[0x11001] == 17 && deinterleaved[0x11002] < 16 &&
|
||||
deinterleaved[0x11027] <= 122 &&
|
||||
deinterleaved[0x11034] == 35 && deinterleaved[0x11035] == 16 &&
|
||||
deinterleaved[0x11036] == 0 &&
|
||||
deinterleaved[0x11037] == 1;
|
||||
|
||||
byte[] tmp = new byte[deinterleaved.Length];
|
||||
|
||||
int[] offsets = extension == ".do"
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(deinterleaved, t * 16 * 256 + offsets[s] * 256, tmp, t * 16 * 256 + s * 256, 256);
|
||||
}
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(tmp, 0, tmp.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
DiscImageChef.DiscImages/AppleDOS/AppleDOS.cs
Normal file
75
DiscImageChef.DiscImages/AppleDOS/AppleDOS.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : AppleDOS.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos : IWritableImage
|
||||
{
|
||||
byte[] deinterleaved;
|
||||
string extension;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public AppleDos()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
40
DiscImageChef.DiscImages/AppleDOS/Constants.cs
Normal file
40
DiscImageChef.DiscImages/AppleDOS/Constants.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
readonly int[] deinterleave = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
readonly int[] interleave = {0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15};
|
||||
}
|
||||
}
|
||||
47
DiscImageChef.DiscImages/AppleDOS/Identify.cs
Normal file
47
DiscImageChef.DiscImages/AppleDOS/Identify.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower();
|
||||
|
||||
return imageFilter.GetDataForkLength() == 143360 && (extension == ".po" || extension == ".do");
|
||||
}
|
||||
}
|
||||
}
|
||||
73
DiscImageChef.DiscImages/AppleDOS/Properties.cs
Normal file
73
DiscImageChef.DiscImages/AppleDOS/Properties.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple ][ Interleaved Disk Image";
|
||||
public Guid Id => new Guid("A5828AC0-62C9-4304-81D4-EFD4AAE47360");
|
||||
|
||||
public string Format =>
|
||||
extension == ".po"
|
||||
? "Apple ][ Interleaved Disk Image (ProDOS order)"
|
||||
: "Apple ][ Interleaved Disk Image (DOS order)";
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
public IEnumerable<MediaType> SupportedMediaTypes => new[] {MediaType.Apple33SS};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".do", ".po"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
103
DiscImageChef.DiscImages/AppleDOS/Read.cs
Normal file
103
DiscImageChef.DiscImages/AppleDOS/Read.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Reads interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
byte[] tmp = new byte[imageFilter.GetDataForkLength()];
|
||||
stream.Read(tmp, 0, tmp.Length);
|
||||
|
||||
bool isDos = tmp[0x11001] == 17 && tmp[0x11002] < 16 && tmp[0x11027] <= 122 && tmp[0x11034] == 35 &&
|
||||
tmp[0x11035] == 16 && tmp[0x11036] == 0 && tmp[0x11037] == 1;
|
||||
|
||||
deinterleaved = new byte[tmp.Length];
|
||||
|
||||
extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower();
|
||||
|
||||
int[] offsets = extension == ".do"
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(tmp, t * 16 * 256 + s * 256, deinterleaved, t * 16 * 256 + offsets[s] * 256, 256);
|
||||
}
|
||||
|
||||
imageInfo.SectorSize = 256;
|
||||
imageInfo.ImageSize = (ulong)imageFilter.GetDataForkLength();
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = 560;
|
||||
imageInfo.MediaType = MediaType.Apple33SS;
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
imageInfo.Cylinders = 35;
|
||||
imageInfo.Heads = 2;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageInfo.SectorSize];
|
||||
|
||||
Array.Copy(deinterleaved, (int)(sectorAddress * imageInfo.SectorSize), buffer, 0, buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
144
DiscImageChef.DiscImages/AppleDOS/Unsupported.cs
Normal file
144
DiscImageChef.DiscImages/AppleDOS/Unsupported.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
}
|
||||
}
|
||||
210
DiscImageChef.DiscImages/AppleDOS/Write.cs
Normal file
210
DiscImageChef.DiscImages/AppleDOS/Write.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes interleaved Apple ][ disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleDos
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 256)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mediaType != MediaType.Apple33SS)
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > uint.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
deinterleaved = new byte[35 * 16 * 256];
|
||||
extension = Path.GetExtension(path);
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
return WriteSectors(data, sectorAddress, 1);
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % imageInfo.SectorSize != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
Array.Copy(data, 0, deinterleaved, (int)(sectorAddress * imageInfo.SectorSize), data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDos = deinterleaved[0x11001] == 17 && deinterleaved[0x11002] < 16 &&
|
||||
deinterleaved[0x11027] <= 122 &&
|
||||
deinterleaved[0x11034] == 35 && deinterleaved[0x11035] == 16 &&
|
||||
deinterleaved[0x11036] == 0 &&
|
||||
deinterleaved[0x11037] == 1;
|
||||
|
||||
byte[] tmp = new byte[deinterleaved.Length];
|
||||
|
||||
int[] offsets = extension == ".do"
|
||||
? (isDos ? deinterleave : interleave)
|
||||
: (isDos ? interleave : deinterleave);
|
||||
|
||||
for(int t = 0; t < 35; t++)
|
||||
{
|
||||
for(int s = 0; s < 16; s++)
|
||||
Array.Copy(deinterleaved, t * 16 * 256 + offsets[s] * 256, tmp, t * 16 * 256 + s * 256, 256);
|
||||
}
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(tmp, 0, tmp.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
DiscImageChef.DiscImages/AppleNIB/AppleNIB.cs
Normal file
75
DiscImageChef.DiscImages/AppleNIB/AppleNIB.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : AppleNIB.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Apple nibbelized disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Checksum sectors
|
||||
public partial class AppleNib : IMediaImage
|
||||
{
|
||||
Dictionary<ulong, byte[]> addressFields;
|
||||
Dictionary<ulong, byte[]> cookedSectors;
|
||||
ImageInfo imageInfo;
|
||||
Dictionary<ulong, byte[]> longSectors;
|
||||
|
||||
public AppleNib()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
53
DiscImageChef.DiscImages/AppleNIB/Constants.cs
Normal file
53
DiscImageChef.DiscImages/AppleNIB/Constants.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleNib
|
||||
{
|
||||
readonly byte[] apple3_sign = {0x8D, 0xD0, 0x03, 0x4C, 0xC7, 0xA4};
|
||||
readonly byte[] cpm_sign = {0xA2, 0x55, 0xA9, 0x00, 0x9D, 0x00, 0x0D, 0xCA};
|
||||
readonly byte[] dos_sign = {0xA2, 0x02, 0x8E, 0x52};
|
||||
readonly ulong[] dosSkewing = {0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15};
|
||||
readonly byte[] dri_string =
|
||||
{
|
||||
0x43, 0x4F, 0x50, 0x59, 0x52, 0x49, 0x47, 0x48, 0x54, 0x20, 0x28, 0x43, 0x29, 0x20, 0x31, 0x39, 0x37, 0x39,
|
||||
0x2C, 0x20, 0x44, 0x49, 0x47, 0x49, 0x54, 0x41, 0x4C, 0x20, 0x52, 0x45, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48
|
||||
};
|
||||
readonly byte[] pascal_sign = {0x08, 0xA5, 0x0F, 0x29};
|
||||
readonly byte[] pascal_string = {0x53, 0x59, 0x53, 0x54, 0x45, 0x2E, 0x41, 0x50, 0x50, 0x4C, 0x45};
|
||||
readonly byte[] pascal2_sign = {0xFF, 0xA2, 0x00, 0x8E};
|
||||
readonly byte[] prodos_string = {0x50, 0x52, 0x4F, 0x44, 0x4F, 0x53};
|
||||
readonly ulong[] proDosSkewing = {0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15};
|
||||
readonly byte[] sos_sign = {0xC9, 0x20, 0xF0, 0x3E};
|
||||
}
|
||||
}
|
||||
49
DiscImageChef.DiscImages/AppleNIB/Helpers.cs
Normal file
49
DiscImageChef.DiscImages/AppleNIB/Helpers.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleNib
|
||||
{
|
||||
MediaType GetMediaType()
|
||||
{
|
||||
switch(imageInfo.Sectors)
|
||||
{
|
||||
case 455: return MediaType.Apple32SS;
|
||||
case 560: return MediaType.Apple33SS;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
DiscImageChef.DiscImages/AppleNIB/Identify.cs
Normal file
54
DiscImageChef.DiscImages/AppleNIB/Identify.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Decoders.Floppy;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleNib
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 512) return false;
|
||||
|
||||
byte[] test = new byte[512];
|
||||
stream.Read(test, 0, 512);
|
||||
|
||||
return Apple2.IsApple2GCR(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
DiscImageChef.DiscImages/AppleNIB/Properties.cs
Normal file
62
DiscImageChef.DiscImages/AppleNIB/Properties.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleNib
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple NIB";
|
||||
public Guid Id => new Guid("AE171AE8-6747-49CC-B861-9D450B7CD42E");
|
||||
|
||||
public string Format => "Apple nibbles";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// /***************************************************************************
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : AppleNIB.cs
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Apple nibbelized disc images.
|
||||
// Reads Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
@@ -38,92 +38,13 @@ using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Decoders.Floppy;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Checksum sectors
|
||||
public class AppleNib : IMediaImage
|
||||
public partial class AppleNib
|
||||
{
|
||||
readonly byte[] apple3_sign = {0x8D, 0xD0, 0x03, 0x4C, 0xC7, 0xA4};
|
||||
readonly byte[] cpm_sign = {0xA2, 0x55, 0xA9, 0x00, 0x9D, 0x00, 0x0D, 0xCA};
|
||||
readonly byte[] dos_sign = {0xA2, 0x02, 0x8E, 0x52};
|
||||
readonly ulong[] dosSkewing = {0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15};
|
||||
readonly byte[] dri_string =
|
||||
{
|
||||
0x43, 0x4F, 0x50, 0x59, 0x52, 0x49, 0x47, 0x48, 0x54, 0x20, 0x28, 0x43, 0x29, 0x20, 0x31, 0x39, 0x37, 0x39,
|
||||
0x2C, 0x20, 0x44, 0x49, 0x47, 0x49, 0x54, 0x41, 0x4C, 0x20, 0x52, 0x45, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48
|
||||
};
|
||||
readonly byte[] pascal_sign = {0x08, 0xA5, 0x0F, 0x29};
|
||||
readonly byte[] pascal_string = {0x53, 0x59, 0x53, 0x54, 0x45, 0x2E, 0x41, 0x50, 0x50, 0x4C, 0x45};
|
||||
readonly byte[] pascal2_sign = {0xFF, 0xA2, 0x00, 0x8E};
|
||||
readonly byte[] prodos_string = {0x50, 0x52, 0x4F, 0x44, 0x4F, 0x53};
|
||||
readonly ulong[] proDosSkewing = {0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15};
|
||||
readonly byte[] sos_sign = {0xC9, 0x20, 0xF0, 0x3E};
|
||||
Dictionary<ulong, byte[]> addressFields;
|
||||
Dictionary<ulong, byte[]> cookedSectors;
|
||||
ImageInfo imageInfo;
|
||||
Dictionary<ulong, byte[]> longSectors;
|
||||
|
||||
public AppleNib()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Apple NIB";
|
||||
public Guid Id => new Guid("AE171AE8-6747-49CC-B861-9D450B7CD42E");
|
||||
|
||||
public string Format => "Apple nibbles";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 512) return false;
|
||||
|
||||
byte[] test = new byte[512];
|
||||
stream.Read(test, 0, 512);
|
||||
|
||||
return Apple2.IsApple2GCR(test);
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
@@ -328,94 +249,5 @@ namespace DiscImageChef.DiscImages
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
MediaType GetMediaType()
|
||||
{
|
||||
switch(imageInfo.Sectors)
|
||||
{
|
||||
case 455: return MediaType.Apple32SS;
|
||||
case 560: return MediaType.Apple33SS;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
118
DiscImageChef.DiscImages/AppleNIB/Unsupported.cs
Normal file
118
DiscImageChef.DiscImages/AppleNIB/Unsupported.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by Apple nibbelized disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class AppleNib
|
||||
{
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,772 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Apridisk.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Apridisk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Check writing
|
||||
public class Apridisk : IWritableImage
|
||||
{
|
||||
readonly byte[] signature =
|
||||
{
|
||||
0x41, 0x43, 0x54, 0x20, 0x41, 0x70, 0x72, 0x69, 0x63, 0x6F, 0x74, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x69,
|
||||
0x6D, 0x61, 0x67, 0x65, 0x1A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
ImageInfo imageInfo;
|
||||
|
||||
// Cylinder by head, sector data matrix
|
||||
byte[][][][] sectorsData;
|
||||
FileStream writingStream;
|
||||
|
||||
public Apridisk()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "ACT Apricot Disk Image";
|
||||
public Guid Id => new Guid("43408CF3-6DB3-449F-A779-2B0E497C5B14");
|
||||
|
||||
public string Format => "ACT Apricot disk image";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < signature.Length) return false;
|
||||
|
||||
byte[] sigB = new byte[signature.Length];
|
||||
stream.Read(sigB, 0, signature.Length);
|
||||
|
||||
return sigB.SequenceEqual(signature);
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Skip signature
|
||||
stream.Seek(signature.Length, SeekOrigin.Begin);
|
||||
|
||||
int totalCylinders = -1;
|
||||
int totalHeads = -1;
|
||||
int maxSector = -1;
|
||||
int recordSize = Marshal.SizeOf(typeof(ApridiskRecord));
|
||||
|
||||
// Count cylinders
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
stream.Read(recB, 0, recordSize);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned);
|
||||
ApridiskRecord record =
|
||||
(ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord));
|
||||
handle.Free();
|
||||
|
||||
switch(record.type)
|
||||
{
|
||||
// Deleted record, just skip it
|
||||
case RecordType.Deleted:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found deleted record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
break;
|
||||
case RecordType.Comment:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found comment record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] commentB = new byte[record.dataSize];
|
||||
stream.Read(commentB, 0, commentB.Length);
|
||||
imageInfo.Comments = StringHandlers.CToString(commentB);
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Comment: \"{0}\"", imageInfo.Comments);
|
||||
break;
|
||||
case RecordType.Creator:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found creator record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] creatorB = new byte[record.dataSize];
|
||||
stream.Read(creatorB, 0, creatorB.Length);
|
||||
imageInfo.Creator = StringHandlers.CToString(creatorB);
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Creator: \"{0}\"", imageInfo.Creator);
|
||||
break;
|
||||
case RecordType.Sector:
|
||||
if(record.compression != CompressType.Compressed &&
|
||||
record.compression != CompressType.Uncompresed)
|
||||
throw new
|
||||
ImageNotSupportedException($"Found record with unknown compression type 0x{(ushort)record.compression:X4} at {stream.Position}");
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin",
|
||||
"Found {4} sector record at {0} for cylinder {1} head {2} sector {3}",
|
||||
stream.Position, record.cylinder, record.head, record.sector,
|
||||
record.compression == CompressType.Compressed
|
||||
? "compressed"
|
||||
: "uncompressed");
|
||||
|
||||
if(record.cylinder > totalCylinders) totalCylinders = record.cylinder;
|
||||
if(record.head > totalHeads) totalHeads = record.head;
|
||||
if(record.sector > maxSector) maxSector = record.sector;
|
||||
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
break;
|
||||
default:
|
||||
throw new
|
||||
ImageNotSupportedException($"Found record with unknown type 0x{(uint)record.type:X8} at {stream.Position}");
|
||||
}
|
||||
}
|
||||
|
||||
totalCylinders++;
|
||||
totalHeads++;
|
||||
|
||||
if(totalCylinders <= 0 || totalHeads <= 0)
|
||||
throw new ImageNotSupportedException("No cylinders or heads found");
|
||||
|
||||
sectorsData = new byte[totalCylinders][][][];
|
||||
// Total sectors per track
|
||||
uint[][] spts = new uint[totalCylinders][];
|
||||
|
||||
imageInfo.Cylinders = (ushort)totalCylinders;
|
||||
imageInfo.Heads = (byte)totalHeads;
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin",
|
||||
"Found {0} cylinders and {1} heads with a maximum sector number of {2}",
|
||||
totalCylinders, totalHeads, maxSector);
|
||||
|
||||
// Create heads
|
||||
for(int i = 0; i < totalCylinders; i++)
|
||||
{
|
||||
sectorsData[i] = new byte[totalHeads][][];
|
||||
spts[i] = new uint[totalHeads];
|
||||
|
||||
for(int j = 0; j < totalHeads; j++) sectorsData[i][j] = new byte[maxSector + 1][];
|
||||
}
|
||||
|
||||
imageInfo.SectorSize = uint.MaxValue;
|
||||
|
||||
ulong headersizes = 0;
|
||||
|
||||
// Read sectors
|
||||
stream.Seek(signature.Length, SeekOrigin.Begin);
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
stream.Read(recB, 0, recordSize);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned);
|
||||
ApridiskRecord record =
|
||||
(ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord));
|
||||
handle.Free();
|
||||
|
||||
switch(record.type)
|
||||
{
|
||||
// Not sector record, just skip it
|
||||
case RecordType.Deleted:
|
||||
case RecordType.Comment:
|
||||
case RecordType.Creator:
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
headersizes += record.headerSize + record.dataSize;
|
||||
break;
|
||||
case RecordType.Sector:
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
|
||||
byte[] data = new byte[record.dataSize];
|
||||
stream.Read(data, 0, data.Length);
|
||||
|
||||
spts[record.cylinder][record.head]++;
|
||||
uint realLength = record.dataSize;
|
||||
|
||||
if(record.compression == CompressType.Compressed)
|
||||
realLength =
|
||||
Decompress(data, out sectorsData[record.cylinder][record.head][record.sector]);
|
||||
else sectorsData[record.cylinder][record.head][record.sector] = data;
|
||||
|
||||
if(realLength < imageInfo.SectorSize) imageInfo.SectorSize = realLength;
|
||||
|
||||
headersizes += record.headerSize + record.dataSize;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found a minimum of {0} bytes per sector",
|
||||
imageInfo.SectorSize);
|
||||
|
||||
// Count sectors per track
|
||||
uint spt = uint.MaxValue;
|
||||
for(ushort cyl = 0; cyl < imageInfo.Cylinders; cyl++)
|
||||
{
|
||||
for(ushort head = 0; head < imageInfo.Heads; head++)
|
||||
if(spts[cyl][head] < spt)
|
||||
spt = spts[cyl][head];
|
||||
}
|
||||
|
||||
imageInfo.SectorsPerTrack = spt;
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found a minimum of {0} sectors per track",
|
||||
imageInfo.SectorsPerTrack);
|
||||
|
||||
imageInfo.MediaType = Geometry.GetMediaType(((ushort)imageInfo.Cylinders, (byte)imageInfo.Heads,
|
||||
(ushort)imageInfo.SectorsPerTrack, 512, MediaEncoding.MFM,
|
||||
false));
|
||||
|
||||
imageInfo.ImageSize = (ulong)stream.Length - headersizes;
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = imageInfo.Cylinders * imageInfo.Heads * imageInfo.SectorsPerTrack;
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
return sectorsData[cylinder][head][sector];
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = ReadSector(sectorAddress + i);
|
||||
buffer.Write(sector, 0, sector.Length);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
// TODO: Test with real hardware to see real supported media
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.ACORN_35_DS_DD, MediaType.ACORN_35_DS_HD, MediaType.Apricot_35, MediaType.ATARI_35_DS_DD,
|
||||
MediaType.ATARI_35_DS_DD_11, MediaType.ATARI_35_SS_DD, MediaType.ATARI_35_SS_DD_11, MediaType.DMF,
|
||||
MediaType.DMF_82, MediaType.DOS_35_DS_DD_8, MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_ED,
|
||||
MediaType.DOS_35_HD, MediaType.DOS_35_SS_DD_8, MediaType.DOS_35_SS_DD_9, MediaType.DOS_525_DS_DD_8,
|
||||
MediaType.DOS_525_DS_DD_9, MediaType.DOS_525_HD, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9,
|
||||
MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_35_HD, MediaType.FDFORMAT_525_DD,
|
||||
MediaType.FDFORMAT_525_HD, MediaType.RX50, MediaType.XDF_35, MediaType.XDF_525
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new[] {("compress", typeof(bool), "Enable Apridisk compression.")};
|
||||
public IEnumerable<string> KnownExtensions => new[] {".dsk"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData[cylinder][head][sector] = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData[cylinder][head][sector] = data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Try if apridisk software supports finding other chunks, to extend metadata support
|
||||
public bool Close()
|
||||
{
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(signature, 0, signature.Length);
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(typeof(ApridiskRecord))];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ApridiskRecord)));
|
||||
|
||||
for(ushort c = 0; c < imageInfo.Cylinders; c++)
|
||||
{
|
||||
for(byte h = 0; h < imageInfo.Heads; h++)
|
||||
{
|
||||
for(byte s = 0; s < imageInfo.SectorsPerTrack; s++)
|
||||
{
|
||||
if(sectorsData[c][h][s] == null || sectorsData[c][h][s].Length == 0) continue;
|
||||
|
||||
ApridiskRecord record = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Sector,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)sectorsData[c][h][s].Length,
|
||||
head = h,
|
||||
sector = s,
|
||||
cylinder = c
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(record, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(sectorsData[c][h][s], 0, sectorsData[c][h][s].Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Creator))
|
||||
{
|
||||
byte[] creatorBytes = Encoding.UTF8.GetBytes(imageInfo.Creator);
|
||||
ApridiskRecord creatorRecord = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Creator,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)creatorBytes.Length + 1,
|
||||
head = 0,
|
||||
sector = 0,
|
||||
cylinder = 0
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(creatorRecord, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(creatorBytes, 0, creatorBytes.Length);
|
||||
writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
{
|
||||
byte[] commentBytes = Encoding.UTF8.GetBytes(imageInfo.Comments);
|
||||
ApridiskRecord commentRecord = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Comment,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)commentBytes.Length + 1,
|
||||
head = 0,
|
||||
sector = 0,
|
||||
cylinder = 0
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(commentRecord, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(commentBytes, 0, commentBytes.Length);
|
||||
writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
imageInfo.Comments = metadata.Comments;
|
||||
imageInfo.Creator = metadata.Creator;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
if(cylinders > ushort.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many cylinders";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(heads > byte.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many heads";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorsPerTrack > byte.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors per track";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData = new byte[cylinders][][][];
|
||||
for(ushort c = 0; c < cylinders; c++)
|
||||
{
|
||||
sectorsData[c] = new byte[heads][][];
|
||||
for(byte h = 0; h < heads; h++) sectorsData[c][h] = new byte[sectorsPerTrack][];
|
||||
}
|
||||
|
||||
imageInfo.Cylinders = cylinders;
|
||||
imageInfo.Heads = heads;
|
||||
imageInfo.SectorsPerTrack = sectorsPerTrack;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint Decompress(byte[] compressed, out byte[] decompressed)
|
||||
{
|
||||
int readp = 0;
|
||||
int cLen = compressed.Length;
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
|
||||
uint uLen = 0;
|
||||
|
||||
while(cLen >= 3)
|
||||
{
|
||||
ushort blklen = BitConverter.ToUInt16(compressed, readp);
|
||||
readp += 2;
|
||||
|
||||
for(int i = 0; i < blklen; i++) buffer.WriteByte(compressed[readp]);
|
||||
|
||||
uLen += blklen;
|
||||
readp++;
|
||||
cLen -= 3;
|
||||
}
|
||||
|
||||
decompressed = buffer.ToArray();
|
||||
return uLen;
|
||||
}
|
||||
|
||||
(ushort cylinder, byte head, byte sector) LbaToChs(ulong lba)
|
||||
{
|
||||
ushort cylinder = (ushort)(lba / (imageInfo.Heads * imageInfo.SectorsPerTrack));
|
||||
byte head = (byte)(lba / imageInfo.SectorsPerTrack % imageInfo.Heads);
|
||||
byte sector = (byte)(lba % imageInfo.SectorsPerTrack + 1);
|
||||
|
||||
return (cylinder, head, sector);
|
||||
}
|
||||
|
||||
enum RecordType : uint
|
||||
{
|
||||
Deleted = 0xE31D0000,
|
||||
Sector = 0xE31D0001,
|
||||
Comment = 0xE31D0002,
|
||||
Creator = 0xE31D0003
|
||||
}
|
||||
|
||||
enum CompressType : ushort
|
||||
{
|
||||
Uncompresed = 0x9E90,
|
||||
Compressed = 0x3E5A
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ApridiskRecord
|
||||
{
|
||||
public RecordType type;
|
||||
public CompressType compression;
|
||||
public ushort headerSize;
|
||||
public uint dataSize;
|
||||
public byte head;
|
||||
public byte sector;
|
||||
public ushort cylinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
DiscImageChef.DiscImages/Apridisk/Apridisk.cs
Normal file
77
DiscImageChef.DiscImages/Apridisk/Apridisk.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Apridisk.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Apridisk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Check writing
|
||||
public partial class Apridisk : IWritableImage
|
||||
{
|
||||
ImageInfo imageInfo;
|
||||
|
||||
// Cylinder by head, sector data matrix
|
||||
byte[][][][] sectorsData;
|
||||
FileStream writingStream;
|
||||
|
||||
public Apridisk()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
64
DiscImageChef.DiscImages/Apridisk/Compression.cs
Normal file
64
DiscImageChef.DiscImages/Apridisk/Compression.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Compression.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains compression algorithm for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
static uint Decompress(byte[] compressed, out byte[] decompressed)
|
||||
{
|
||||
int readp = 0;
|
||||
int cLen = compressed.Length;
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
|
||||
uint uLen = 0;
|
||||
|
||||
while(cLen >= 3)
|
||||
{
|
||||
ushort blklen = BitConverter.ToUInt16(compressed, readp);
|
||||
readp += 2;
|
||||
|
||||
for(int i = 0; i < blklen; i++) buffer.WriteByte(compressed[readp]);
|
||||
|
||||
uLen += blklen;
|
||||
readp++;
|
||||
cLen -= 3;
|
||||
}
|
||||
|
||||
decompressed = buffer.ToArray();
|
||||
return uLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
DiscImageChef.DiscImages/Apridisk/Constants.cs
Normal file
49
DiscImageChef.DiscImages/Apridisk/Constants.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
readonly byte[] signature =
|
||||
{
|
||||
0x41, 0x43, 0x54, 0x20, 0x41, 0x70, 0x72, 0x69, 0x63, 0x6F, 0x74, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x69,
|
||||
0x6D, 0x61, 0x67, 0x65, 0x1A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
}
|
||||
}
|
||||
51
DiscImageChef.DiscImages/Apridisk/Enums.cs
Normal file
51
DiscImageChef.DiscImages/Apridisk/Enums.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
enum RecordType : uint
|
||||
{
|
||||
Deleted = 0xE31D0000,
|
||||
Sector = 0xE31D0001,
|
||||
Comment = 0xE31D0002,
|
||||
Creator = 0xE31D0003
|
||||
}
|
||||
|
||||
enum CompressType : ushort
|
||||
{
|
||||
Uncompresed = 0x9E90,
|
||||
Compressed = 0x3E5A
|
||||
}
|
||||
}
|
||||
}
|
||||
46
DiscImageChef.DiscImages/Apridisk/Helpers.cs
Normal file
46
DiscImageChef.DiscImages/Apridisk/Helpers.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) LbaToChs(ulong lba)
|
||||
{
|
||||
ushort cylinder = (ushort)(lba / (imageInfo.Heads * imageInfo.SectorsPerTrack));
|
||||
byte head = (byte)(lba / imageInfo.SectorsPerTrack % imageInfo.Heads);
|
||||
byte sector = (byte)(lba % imageInfo.SectorsPerTrack + 1);
|
||||
|
||||
return (cylinder, head, sector);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
DiscImageChef.DiscImages/Apridisk/Identify.cs
Normal file
54
DiscImageChef.DiscImages/Apridisk/Identify.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < signature.Length) return false;
|
||||
|
||||
byte[] sigB = new byte[signature.Length];
|
||||
stream.Read(sigB, 0, signature.Length);
|
||||
|
||||
return sigB.SequenceEqual(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
DiscImageChef.DiscImages/Apridisk/Properties.cs
Normal file
83
DiscImageChef.DiscImages/Apridisk/Properties.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "ACT Apricot Disk Image";
|
||||
public Guid Id => new Guid("43408CF3-6DB3-449F-A779-2B0E497C5B14");
|
||||
|
||||
public string Format => "ACT Apricot disk image";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new SectorTagType[] { };
|
||||
// TODO: Test with real hardware to see real supported media
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.ACORN_35_DS_DD, MediaType.ACORN_35_DS_HD, MediaType.Apricot_35, MediaType.ATARI_35_DS_DD,
|
||||
MediaType.ATARI_35_DS_DD_11, MediaType.ATARI_35_SS_DD, MediaType.ATARI_35_SS_DD_11, MediaType.DMF,
|
||||
MediaType.DMF_82, MediaType.DOS_35_DS_DD_8, MediaType.DOS_35_DS_DD_9, MediaType.DOS_35_ED,
|
||||
MediaType.DOS_35_HD, MediaType.DOS_35_SS_DD_8, MediaType.DOS_35_SS_DD_9, MediaType.DOS_525_DS_DD_8,
|
||||
MediaType.DOS_525_DS_DD_9, MediaType.DOS_525_HD, MediaType.DOS_525_SS_DD_8, MediaType.DOS_525_SS_DD_9,
|
||||
MediaType.FDFORMAT_35_DD, MediaType.FDFORMAT_35_HD, MediaType.FDFORMAT_525_DD,
|
||||
MediaType.FDFORMAT_525_HD, MediaType.RX50, MediaType.XDF_35, MediaType.XDF_525
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new[] {("compress", typeof(bool), "Enable Apridisk compression.")};
|
||||
public IEnumerable<string> KnownExtensions => new[] {".dsk"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
256
DiscImageChef.DiscImages/Apridisk/Read.cs
Normal file
256
DiscImageChef.DiscImages/Apridisk/Read.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Reads Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Skip signature
|
||||
stream.Seek(signature.Length, SeekOrigin.Begin);
|
||||
|
||||
int totalCylinders = -1;
|
||||
int totalHeads = -1;
|
||||
int maxSector = -1;
|
||||
int recordSize = Marshal.SizeOf(typeof(ApridiskRecord));
|
||||
|
||||
// Count cylinders
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
stream.Read(recB, 0, recordSize);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned);
|
||||
ApridiskRecord record =
|
||||
(ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord));
|
||||
handle.Free();
|
||||
|
||||
switch(record.type)
|
||||
{
|
||||
// Deleted record, just skip it
|
||||
case RecordType.Deleted:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found deleted record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
break;
|
||||
case RecordType.Comment:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found comment record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] commentB = new byte[record.dataSize];
|
||||
stream.Read(commentB, 0, commentB.Length);
|
||||
imageInfo.Comments = StringHandlers.CToString(commentB);
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Comment: \"{0}\"", imageInfo.Comments);
|
||||
break;
|
||||
case RecordType.Creator:
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found creator record at {0}", stream.Position);
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
byte[] creatorB = new byte[record.dataSize];
|
||||
stream.Read(creatorB, 0, creatorB.Length);
|
||||
imageInfo.Creator = StringHandlers.CToString(creatorB);
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Creator: \"{0}\"", imageInfo.Creator);
|
||||
break;
|
||||
case RecordType.Sector:
|
||||
if(record.compression != CompressType.Compressed &&
|
||||
record.compression != CompressType.Uncompresed)
|
||||
throw new
|
||||
ImageNotSupportedException($"Found record with unknown compression type 0x{(ushort)record.compression:X4} at {stream.Position}");
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin",
|
||||
"Found {4} sector record at {0} for cylinder {1} head {2} sector {3}",
|
||||
stream.Position, record.cylinder, record.head, record.sector,
|
||||
record.compression == CompressType.Compressed
|
||||
? "compressed"
|
||||
: "uncompressed");
|
||||
|
||||
if(record.cylinder > totalCylinders) totalCylinders = record.cylinder;
|
||||
if(record.head > totalHeads) totalHeads = record.head;
|
||||
if(record.sector > maxSector) maxSector = record.sector;
|
||||
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
break;
|
||||
default:
|
||||
throw new
|
||||
ImageNotSupportedException($"Found record with unknown type 0x{(uint)record.type:X8} at {stream.Position}");
|
||||
}
|
||||
}
|
||||
|
||||
totalCylinders++;
|
||||
totalHeads++;
|
||||
|
||||
if(totalCylinders <= 0 || totalHeads <= 0)
|
||||
throw new ImageNotSupportedException("No cylinders or heads found");
|
||||
|
||||
sectorsData = new byte[totalCylinders][][][];
|
||||
// Total sectors per track
|
||||
uint[][] spts = new uint[totalCylinders][];
|
||||
|
||||
imageInfo.Cylinders = (ushort)totalCylinders;
|
||||
imageInfo.Heads = (byte)totalHeads;
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin",
|
||||
"Found {0} cylinders and {1} heads with a maximum sector number of {2}",
|
||||
totalCylinders, totalHeads, maxSector);
|
||||
|
||||
// Create heads
|
||||
for(int i = 0; i < totalCylinders; i++)
|
||||
{
|
||||
sectorsData[i] = new byte[totalHeads][][];
|
||||
spts[i] = new uint[totalHeads];
|
||||
|
||||
for(int j = 0; j < totalHeads; j++) sectorsData[i][j] = new byte[maxSector + 1][];
|
||||
}
|
||||
|
||||
imageInfo.SectorSize = uint.MaxValue;
|
||||
|
||||
ulong headersizes = 0;
|
||||
|
||||
// Read sectors
|
||||
stream.Seek(signature.Length, SeekOrigin.Begin);
|
||||
while(stream.Position < stream.Length)
|
||||
{
|
||||
byte[] recB = new byte[recordSize];
|
||||
stream.Read(recB, 0, recordSize);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned);
|
||||
ApridiskRecord record =
|
||||
(ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord));
|
||||
handle.Free();
|
||||
|
||||
switch(record.type)
|
||||
{
|
||||
// Not sector record, just skip it
|
||||
case RecordType.Deleted:
|
||||
case RecordType.Comment:
|
||||
case RecordType.Creator:
|
||||
stream.Seek(record.headerSize - recordSize + record.dataSize, SeekOrigin.Current);
|
||||
headersizes += record.headerSize + record.dataSize;
|
||||
break;
|
||||
case RecordType.Sector:
|
||||
stream.Seek(record.headerSize - recordSize, SeekOrigin.Current);
|
||||
|
||||
byte[] data = new byte[record.dataSize];
|
||||
stream.Read(data, 0, data.Length);
|
||||
|
||||
spts[record.cylinder][record.head]++;
|
||||
uint realLength = record.dataSize;
|
||||
|
||||
if(record.compression == CompressType.Compressed)
|
||||
realLength =
|
||||
Decompress(data, out sectorsData[record.cylinder][record.head][record.sector]);
|
||||
else sectorsData[record.cylinder][record.head][record.sector] = data;
|
||||
|
||||
if(realLength < imageInfo.SectorSize) imageInfo.SectorSize = realLength;
|
||||
|
||||
headersizes += record.headerSize + record.dataSize;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found a minimum of {0} bytes per sector",
|
||||
imageInfo.SectorSize);
|
||||
|
||||
// Count sectors per track
|
||||
uint spt = uint.MaxValue;
|
||||
for(ushort cyl = 0; cyl < imageInfo.Cylinders; cyl++)
|
||||
{
|
||||
for(ushort head = 0; head < imageInfo.Heads; head++)
|
||||
if(spts[cyl][head] < spt)
|
||||
spt = spts[cyl][head];
|
||||
}
|
||||
|
||||
imageInfo.SectorsPerTrack = spt;
|
||||
|
||||
DicConsole.DebugWriteLine("Apridisk plugin", "Found a minimum of {0} sectors per track",
|
||||
imageInfo.SectorsPerTrack);
|
||||
|
||||
imageInfo.MediaType = Geometry.GetMediaType(((ushort)imageInfo.Cylinders, (byte)imageInfo.Heads,
|
||||
(ushort)imageInfo.SectorsPerTrack, 512, MediaEncoding.MFM,
|
||||
false));
|
||||
|
||||
imageInfo.ImageSize = (ulong)stream.Length - headersizes;
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
imageInfo.Sectors = imageInfo.Cylinders * imageInfo.Heads * imageInfo.SectorsPerTrack;
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
return sectorsData[cylinder][head][sector];
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
byte[] sector = ReadSector(sectorAddress + i);
|
||||
buffer.Write(sector, 0, sector.Length);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
51
DiscImageChef.DiscImages/Apridisk/Structs.cs
Normal file
51
DiscImageChef.DiscImages/Apridisk/Structs.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ApridiskRecord
|
||||
{
|
||||
public RecordType type;
|
||||
public CompressType compression;
|
||||
public ushort headerSize;
|
||||
public uint dataSize;
|
||||
public byte head;
|
||||
public byte sector;
|
||||
public ushort cylinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
138
DiscImageChef.DiscImages/Apridisk/Unsupported.cs
Normal file
138
DiscImageChef.DiscImages/Apridisk/Unsupported.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
for(ulong i = 0; i < imageInfo.Sectors; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
307
DiscImageChef.DiscImages/Apridisk/Write.cs
Normal file
307
DiscImageChef.DiscImages/Apridisk/Write.cs
Normal file
@@ -0,0 +1,307 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes Apridisk disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Apridisk
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData[cylinder][head][sector] = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
(ushort cylinder, byte head, byte sector) = LbaToChs(sectorAddress);
|
||||
|
||||
if(cylinder >= sectorsData.Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(head >= sectorsData[cylinder].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sector > sectorsData[cylinder][head].Length)
|
||||
{
|
||||
ErrorMessage = "Sector address not found";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData[cylinder][head][sector] = data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
ErrorMessage = "Writing sectors with tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Try if apridisk software supports finding other chunks, to extend metadata support
|
||||
public bool Close()
|
||||
{
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(signature, 0, signature.Length);
|
||||
|
||||
byte[] hdr = new byte[Marshal.SizeOf(typeof(ApridiskRecord))];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ApridiskRecord)));
|
||||
|
||||
for(ushort c = 0; c < imageInfo.Cylinders; c++)
|
||||
{
|
||||
for(byte h = 0; h < imageInfo.Heads; h++)
|
||||
{
|
||||
for(byte s = 0; s < imageInfo.SectorsPerTrack; s++)
|
||||
{
|
||||
if(sectorsData[c][h][s] == null || sectorsData[c][h][s].Length == 0) continue;
|
||||
|
||||
ApridiskRecord record = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Sector,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)sectorsData[c][h][s].Length,
|
||||
head = h,
|
||||
sector = s,
|
||||
cylinder = c
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(record, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(sectorsData[c][h][s], 0, sectorsData[c][h][s].Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Creator))
|
||||
{
|
||||
byte[] creatorBytes = Encoding.UTF8.GetBytes(imageInfo.Creator);
|
||||
ApridiskRecord creatorRecord = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Creator,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)creatorBytes.Length + 1,
|
||||
head = 0,
|
||||
sector = 0,
|
||||
cylinder = 0
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(creatorRecord, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(creatorBytes, 0, creatorBytes.Length);
|
||||
writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(imageInfo.Comments))
|
||||
{
|
||||
byte[] commentBytes = Encoding.UTF8.GetBytes(imageInfo.Comments);
|
||||
ApridiskRecord commentRecord = new ApridiskRecord
|
||||
{
|
||||
type = RecordType.Comment,
|
||||
compression = CompressType.Uncompresed,
|
||||
headerSize = (ushort)Marshal.SizeOf(typeof(ApridiskRecord)),
|
||||
dataSize = (uint)commentBytes.Length + 1,
|
||||
head = 0,
|
||||
sector = 0,
|
||||
cylinder = 0
|
||||
};
|
||||
|
||||
Marshal.StructureToPtr(commentRecord, hdrPtr, true);
|
||||
Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
|
||||
|
||||
writingStream.Write(hdr, 0, hdr.Length);
|
||||
writingStream.Write(commentBytes, 0, commentBytes.Length);
|
||||
writingStream.WriteByte(0); // Termination
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(hdrPtr);
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
imageInfo.Comments = metadata.Comments;
|
||||
imageInfo.Creator = metadata.Creator;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
if(cylinders > ushort.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many cylinders";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(heads > byte.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many heads";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorsPerTrack > byte.MaxValue)
|
||||
{
|
||||
ErrorMessage = "Too many sectors per track";
|
||||
return false;
|
||||
}
|
||||
|
||||
sectorsData = new byte[cylinders][][][];
|
||||
for(ushort c = 0; c < cylinders; c++)
|
||||
{
|
||||
sectorsData[c] = new byte[heads][][];
|
||||
for(byte h = 0; h < heads; h++) sectorsData[c][h] = new byte[sectorsPerTrack][];
|
||||
}
|
||||
|
||||
imageInfo.Cylinders = cylinders;
|
||||
imageInfo.Heads = heads;
|
||||
imageInfo.SectorsPerTrack = sectorsPerTrack;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,782 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BLU.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Decoders;
|
||||
using Schemas;
|
||||
using Version = DiscImageChef.CommonTypes.Interop.Version;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public class Blu : IWritableImage
|
||||
{
|
||||
const string PROFILE_NAME = "PROFILE ";
|
||||
const string PROFILE10_NAME = "PROFILE 10 ";
|
||||
const string WIDGET_NAME = "WIDGET-10 ";
|
||||
const string PRIAM_NAME = "PRIAMDTATOWER";
|
||||
IFilter bluImageFilter;
|
||||
int bptag;
|
||||
|
||||
BluHeader imageHeader;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Blu()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "Basic Lisa Utility";
|
||||
public Guid Id => new Guid("A153E2F8-4235-432D-9A7F-20807B0BCD74");
|
||||
|
||||
public string Format => "Basic Lisa Utility";
|
||||
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 0x200) return false;
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
stream.Read(header, 0, 0x17);
|
||||
|
||||
BluHeader tmpHdr = new BluHeader {DeviceName = new byte[0x0D]};
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
Array.Copy(header, 0, tmpHdr.DeviceName, 0, 0x0D);
|
||||
tmpHdr.DeviceType = BigEndianBitConverter.ToUInt32(header, 0x0C) & 0x00FFFFFF;
|
||||
tmpHdr.DeviceBlocks = BigEndianBitConverter.ToUInt32(header, 0x11) & 0x00FFFFFF;
|
||||
tmpHdr.BytesPerBlock = BigEndianBitConverter.ToUInt16(header, 0x15);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
if(tmpHdr.DeviceName[i] < 0x20)
|
||||
return false;
|
||||
|
||||
return (tmpHdr.BytesPerBlock & 0xFE00) == 0x200;
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
imageHeader = new BluHeader {DeviceName = new byte[0x0D]};
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
stream.Read(header, 0, 0x17);
|
||||
Array.Copy(header, 0, imageHeader.DeviceName, 0, 0x0D);
|
||||
imageHeader.DeviceType = BigEndianBitConverter.ToUInt32(header, 0x0C) & 0x00FFFFFF;
|
||||
imageHeader.DeviceBlocks = BigEndianBitConverter.ToUInt32(header, 0x11) & 0x00FFFFFF;
|
||||
imageHeader.BytesPerBlock = BigEndianBitConverter.ToUInt16(header, 0x15);
|
||||
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceName = \"{0}\"",
|
||||
StringHandlers.CToString(imageHeader.DeviceName));
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceType = {0}", imageHeader.DeviceType);
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceBlock = {0}", imageHeader.DeviceBlocks);
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.bytesPerBlock = {0}", imageHeader.BytesPerBlock);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
if(imageHeader.DeviceName[i] < 0x20)
|
||||
return false;
|
||||
|
||||
if((imageHeader.BytesPerBlock & 0xFE00) != 0x200) return false;
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
header = new byte[imageHeader.BytesPerBlock];
|
||||
stream.Read(header, 0, imageHeader.BytesPerBlock);
|
||||
|
||||
imageInfo.SectorSize = 0x200;
|
||||
|
||||
imageInfo.Sectors = imageHeader.DeviceBlocks;
|
||||
imageInfo.ImageSize = imageHeader.DeviceBlocks * imageHeader.BytesPerBlock;
|
||||
bptag = imageHeader.BytesPerBlock - 0x200;
|
||||
byte[] hdrTag = new byte[bptag];
|
||||
Array.Copy(header, 0x200, hdrTag, 0, bptag);
|
||||
|
||||
switch(StringHandlers.CToString(imageHeader.DeviceName))
|
||||
{
|
||||
case PROFILE_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x2600 ? MediaType.AppleProfile : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 152;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case PROFILE10_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x4C00 ? MediaType.AppleProfile : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 304;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case WIDGET_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x4C00 ? MediaType.AppleWidget : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 304;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case PRIAM_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x022C7C ? MediaType.PriamDataTower : MediaType.GENERIC_HDD;
|
||||
// This values are invented...
|
||||
imageInfo.Cylinders = 419;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 85;
|
||||
break;
|
||||
default:
|
||||
imageInfo.MediaType = MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = (uint)(imageInfo.Sectors / 16 / 63);
|
||||
imageInfo.Heads = 16;
|
||||
imageInfo.SectorsPerTrack = 63;
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.Application = StringHandlers.CToString(hdrTag);
|
||||
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
|
||||
bluImageFilter = imageFilter;
|
||||
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
if(bptag > 0) imageInfo.ReadableSectorTags.Add(SectorTagType.AppleSectorTag);
|
||||
|
||||
DicConsole.VerboseWriteLine("BLU image contains a disk of type {0}", imageInfo.MediaType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
return ReadSectorsTag(sectorAddress, 1, tag);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
int seek = 0;
|
||||
int read = 0x200;
|
||||
int skip = bptag;
|
||||
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
stream.Seek(seek, SeekOrigin.Current);
|
||||
byte[] sector = new byte[read];
|
||||
stream.Read(sector, 0, read);
|
||||
buffer.Write(sector, 0, read);
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
if(tag != SectorTagType.AppleSectorTag)
|
||||
throw new FeatureUnsupportedImageException($"Tag {tag} not supported by image format");
|
||||
|
||||
if(bptag == 0) throw new FeatureNotPresentImageException("Disk image does not have tags");
|
||||
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
int seek = 0x200;
|
||||
int read = bptag;
|
||||
int skip = 0;
|
||||
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
stream.Seek(seek, SeekOrigin.Current);
|
||||
byte[] sector = new byte[read];
|
||||
stream.Read(sector, 0, read);
|
||||
buffer.Write(sector, 0, read);
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectorsLong(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageHeader.BytesPerBlock];
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
// TODO: Check tag checkums
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new[] {SectorTagType.AppleSectorTag};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.AppleProfile, MediaType.AppleWidget, MediaType.PriamDataTower, MediaType.GENERIC_HDD,
|
||||
MediaType.Unknown, MediaType.FlashDrive, MediaType.CompactFlash, MediaType.CompactFlashType2,
|
||||
MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII, MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".blu"}; // Just invented
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > 0xFFFFFF)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != 512)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % 512 != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
byte[] oldTag;
|
||||
byte[] newTag;
|
||||
|
||||
switch(data.Length - 512)
|
||||
{
|
||||
// Sony tag, convert to Profile
|
||||
case 12 when longSectorSize == 532:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Sony tag, convert to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Profile tag, copy to Profile
|
||||
case 20 when longSectorSize == 532:
|
||||
newTag = new byte[20];
|
||||
Array.Copy(data, 512, newTag, 0, 20);
|
||||
break;
|
||||
// Profile tag, convert to Priam
|
||||
case 20 when longSectorSize == 536:
|
||||
oldTag = new byte[20];
|
||||
Array.Copy(data, 512, oldTag, 0, 20);
|
||||
newTag = LisaTag.DecodeProfileTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Priam tag, convert to Profile
|
||||
case 24 when longSectorSize == 532:
|
||||
oldTag = new byte[24];
|
||||
Array.Copy(data, 512, oldTag, 0, 24);
|
||||
newTag = LisaTag.DecodePriamTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Priam tag, copy to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
newTag = new byte[24];
|
||||
Array.Copy(data, 512, newTag, 0, 24);
|
||||
break;
|
||||
case 0:
|
||||
newTag = null;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(newTag == null) newTag = new byte[longSectorSize - 512];
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, 512);
|
||||
writingStream.Write(newTag, 0, newTag.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
long givenSectorSize = data.Length / length;
|
||||
|
||||
switch(givenSectorSize)
|
||||
{
|
||||
case 536:
|
||||
case 532:
|
||||
case 524:
|
||||
case 512: break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
byte[] oldTag;
|
||||
byte[] newTag;
|
||||
|
||||
switch(givenSectorSize - 512)
|
||||
{
|
||||
// Sony tag, convert to Profile
|
||||
case 12 when longSectorSize == 532:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Sony tag, convert to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Profile tag, copy to Profile
|
||||
case 20 when longSectorSize == 532:
|
||||
newTag = new byte[20];
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 20);
|
||||
break;
|
||||
// Profile tag, convert to Priam
|
||||
case 20 when longSectorSize == 536:
|
||||
oldTag = new byte[20];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 20);
|
||||
newTag = LisaTag.DecodeProfileTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Priam tag, convert to Profile
|
||||
case 24 when longSectorSize == 532:
|
||||
oldTag = new byte[24];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 24);
|
||||
newTag = LisaTag.DecodePriamTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Priam tag, copy to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
newTag = new byte[24];
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 24);
|
||||
break;
|
||||
case 0:
|
||||
newTag = null;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(newTag == null) newTag = new byte[longSectorSize - 512];
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, (int)(givenSectorSize * i), 512);
|
||||
writingStream.Write(newTag, 0, newTag.Length);
|
||||
}
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
byte[] markerTag = Encoding.UTF8.GetBytes("DiscImageChef " + Version.GetVersion());
|
||||
byte[] driveName;
|
||||
byte[] driveType = new byte[3];
|
||||
byte[] driveBlocks = BigEndianBitConverter.GetBytes((uint)imageInfo.Sectors);
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
byte[] blockSize = BigEndianBitConverter.GetBytes((ushort)longSectorSize);
|
||||
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
case MediaType.AppleProfile when imageInfo.Sectors == 0x4C00:
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE10_NAME);
|
||||
break;
|
||||
case MediaType.AppleWidget when imageInfo.Sectors == 0x4C00:
|
||||
driveType[1] = 0x01;
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE10_NAME);
|
||||
break;
|
||||
case MediaType.PriamDataTower when imageInfo.Sectors == 0x22C7C:
|
||||
driveType[1] = 0xFF;
|
||||
driveName = Encoding.ASCII.GetBytes(PRIAM_NAME);
|
||||
break;
|
||||
default:
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE_NAME);
|
||||
break;
|
||||
}
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(driveName, 0, driveName.Length >= 0xD ? 0xD : driveName.Length);
|
||||
writingStream.Seek(0xD, SeekOrigin.Begin);
|
||||
writingStream.Write(driveType, 0, 3);
|
||||
writingStream.Seek(0x12, SeekOrigin.Begin);
|
||||
writingStream.Write(driveBlocks, 1, 3);
|
||||
writingStream.Seek(0x15, SeekOrigin.Begin);
|
||||
writingStream.Write(blockSize, 1, 2);
|
||||
writingStream.Seek(512, SeekOrigin.Begin);
|
||||
writingStream.Write(markerTag, 0,
|
||||
markerTag.Length >= longSectorSize - 512 ? longSectorSize - 512 : markerTag.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
struct BluHeader
|
||||
{
|
||||
public byte[] DeviceName;
|
||||
public uint DeviceType;
|
||||
public uint DeviceBlocks;
|
||||
public ushort BytesPerBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
84
DiscImageChef.DiscImages/BLU/BLU.cs
Normal file
84
DiscImageChef.DiscImages/BLU/BLU.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BLU.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu : IWritableImage
|
||||
{
|
||||
IFilter bluImageFilter;
|
||||
int bptag;
|
||||
BluHeader imageHeader;
|
||||
ImageInfo imageInfo;
|
||||
FileStream writingStream;
|
||||
|
||||
public Blu()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Version = null,
|
||||
Application = null,
|
||||
ApplicationVersion = null,
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
struct BluHeader
|
||||
{
|
||||
public byte[] DeviceName;
|
||||
public uint DeviceType;
|
||||
public uint DeviceBlocks;
|
||||
public ushort BytesPerBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
DiscImageChef.DiscImages/BLU/Constants.cs
Normal file
42
DiscImageChef.DiscImages/BLU/Constants.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
const string PROFILE_NAME = "PROFILE ";
|
||||
const string PROFILE10_NAME = "PROFILE 10 ";
|
||||
const string WIDGET_NAME = "WIDGET-10 ";
|
||||
const string PRIAM_NAME = "PRIAMDTATOWER";
|
||||
}
|
||||
}
|
||||
66
DiscImageChef.DiscImages/BLU/Identify.cs
Normal file
66
DiscImageChef.DiscImages/BLU/Identify.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if(stream.Length < 0x200) return false;
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
stream.Read(header, 0, 0x17);
|
||||
|
||||
BluHeader tmpHdr = new BluHeader {DeviceName = new byte[0x0D]};
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
Array.Copy(header, 0, tmpHdr.DeviceName, 0, 0x0D);
|
||||
tmpHdr.DeviceType = BigEndianBitConverter.ToUInt32(header, 0x0C) & 0x00FFFFFF;
|
||||
tmpHdr.DeviceBlocks = BigEndianBitConverter.ToUInt32(header, 0x11) & 0x00FFFFFF;
|
||||
tmpHdr.BytesPerBlock = BigEndianBitConverter.ToUInt16(header, 0x15);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
if(tmpHdr.DeviceName[i] < 0x20)
|
||||
return false;
|
||||
|
||||
return (tmpHdr.BytesPerBlock & 0xFE00) == 0x200;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
DiscImageChef.DiscImages/BLU/Properties.cs
Normal file
72
DiscImageChef.DiscImages/BLU/Properties.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
public string Name => "Basic Lisa Utility";
|
||||
public Guid Id => new Guid("A153E2F8-4235-432D-9A7F-20807B0BCD74");
|
||||
public string Format => "Basic Lisa Utility";
|
||||
public List<Partition> Partitions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<Track> Tracks =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<Session> Sessions =>
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new MediaTagType[] { };
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags => new[] {SectorTagType.AppleSectorTag};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.AppleProfile, MediaType.AppleWidget, MediaType.PriamDataTower, MediaType.GENERIC_HDD,
|
||||
MediaType.Unknown, MediaType.FlashDrive, MediaType.CompactFlash, MediaType.CompactFlashType2,
|
||||
MediaType.PCCardTypeI, MediaType.PCCardTypeII, MediaType.PCCardTypeIII, MediaType.PCCardTypeIV
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new (string name, Type type, string description)[] { };
|
||||
public IEnumerable<string> KnownExtensions => new[] {".blu"}; // Just invented
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
250
DiscImageChef.DiscImages/BLU/Read.cs
Normal file
250
DiscImageChef.DiscImages/BLU/Read.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Reads Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
imageHeader = new BluHeader {DeviceName = new byte[0x0D]};
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
byte[] header = new byte[0x17];
|
||||
stream.Read(header, 0, 0x17);
|
||||
Array.Copy(header, 0, imageHeader.DeviceName, 0, 0x0D);
|
||||
imageHeader.DeviceType = BigEndianBitConverter.ToUInt32(header, 0x0C) & 0x00FFFFFF;
|
||||
imageHeader.DeviceBlocks = BigEndianBitConverter.ToUInt32(header, 0x11) & 0x00FFFFFF;
|
||||
imageHeader.BytesPerBlock = BigEndianBitConverter.ToUInt16(header, 0x15);
|
||||
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceName = \"{0}\"",
|
||||
StringHandlers.CToString(imageHeader.DeviceName));
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceType = {0}", imageHeader.DeviceType);
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.deviceBlock = {0}", imageHeader.DeviceBlocks);
|
||||
DicConsole.DebugWriteLine("BLU plugin", "ImageHeader.bytesPerBlock = {0}", imageHeader.BytesPerBlock);
|
||||
|
||||
for(int i = 0; i < 0xD; i++)
|
||||
if(imageHeader.DeviceName[i] < 0x20)
|
||||
return false;
|
||||
|
||||
if((imageHeader.BytesPerBlock & 0xFE00) != 0x200) return false;
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
header = new byte[imageHeader.BytesPerBlock];
|
||||
stream.Read(header, 0, imageHeader.BytesPerBlock);
|
||||
|
||||
imageInfo.SectorSize = 0x200;
|
||||
|
||||
imageInfo.Sectors = imageHeader.DeviceBlocks;
|
||||
imageInfo.ImageSize = imageHeader.DeviceBlocks * imageHeader.BytesPerBlock;
|
||||
bptag = imageHeader.BytesPerBlock - 0x200;
|
||||
byte[] hdrTag = new byte[bptag];
|
||||
Array.Copy(header, 0x200, hdrTag, 0, bptag);
|
||||
|
||||
switch(StringHandlers.CToString(imageHeader.DeviceName))
|
||||
{
|
||||
case PROFILE_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x2600 ? MediaType.AppleProfile : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 152;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case PROFILE10_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x4C00 ? MediaType.AppleProfile : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 304;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case WIDGET_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x4C00 ? MediaType.AppleWidget : MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = 304;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 16;
|
||||
break;
|
||||
case PRIAM_NAME:
|
||||
imageInfo.MediaType =
|
||||
imageInfo.Sectors == 0x022C7C ? MediaType.PriamDataTower : MediaType.GENERIC_HDD;
|
||||
// This values are invented...
|
||||
imageInfo.Cylinders = 419;
|
||||
imageInfo.Heads = 4;
|
||||
imageInfo.SectorsPerTrack = 85;
|
||||
break;
|
||||
default:
|
||||
imageInfo.MediaType = MediaType.GENERIC_HDD;
|
||||
imageInfo.Cylinders = (uint)(imageInfo.Sectors / 16 / 63);
|
||||
imageInfo.Heads = 16;
|
||||
imageInfo.SectorsPerTrack = 63;
|
||||
break;
|
||||
}
|
||||
|
||||
imageInfo.Application = StringHandlers.CToString(hdrTag);
|
||||
|
||||
imageInfo.CreationTime = imageFilter.GetCreationTime();
|
||||
imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
|
||||
imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
||||
|
||||
bluImageFilter = imageFilter;
|
||||
|
||||
imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
|
||||
|
||||
if(bptag > 0) imageInfo.ReadableSectorTags.Add(SectorTagType.AppleSectorTag);
|
||||
|
||||
DicConsole.VerboseWriteLine("BLU image contains a disk of type {0}", imageInfo.MediaType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectors(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
return ReadSectorsTag(sectorAddress, 1, tag);
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
int seek = 0;
|
||||
int read = 0x200;
|
||||
int skip = bptag;
|
||||
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
stream.Seek(seek, SeekOrigin.Current);
|
||||
byte[] sector = new byte[read];
|
||||
stream.Read(sector, 0, read);
|
||||
buffer.Write(sector, 0, read);
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
if(tag != SectorTagType.AppleSectorTag)
|
||||
throw new FeatureUnsupportedImageException($"Tag {tag} not supported by image format");
|
||||
|
||||
if(bptag == 0) throw new FeatureNotPresentImageException("Disk image does not have tags");
|
||||
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
int seek = 0x200;
|
||||
int read = bptag;
|
||||
int skip = 0;
|
||||
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
stream.Seek(seek, SeekOrigin.Current);
|
||||
byte[] sector = new byte[read];
|
||||
stream.Read(sector, 0, read);
|
||||
buffer.Write(sector, 0, read);
|
||||
stream.Seek(skip, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress)
|
||||
{
|
||||
return ReadSectorsLong(sectorAddress, 1);
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
||||
{
|
||||
if(sectorAddress > imageInfo.Sectors - 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found");
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available");
|
||||
|
||||
byte[] buffer = new byte[length * imageHeader.BytesPerBlock];
|
||||
Stream stream = bluImageFilter.GetDataForkStream();
|
||||
stream.Seek((long)((sectorAddress + 1) * imageHeader.BytesPerBlock), SeekOrigin.Begin);
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// TODO: Check tag checkums
|
||||
public bool? VerifySector(ulong sectorAddress)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
DiscImageChef.DiscImages/BLU/Unsupported.cs
Normal file
108
DiscImageChef.DiscImages/BLU/Unsupported.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
public byte[] ReadDiskTag(MediaTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(Session session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public List<Track> GetSessionTracks(ushort session)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSector(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
||||
{
|
||||
throw new FeatureUnsupportedImageException("Feature not supported by image format");
|
||||
}
|
||||
|
||||
public bool? VerifySector(ulong sectorAddress, uint track)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
||||
out List<ulong> unknownLbas)
|
||||
{
|
||||
failingLbas = new List<ulong>();
|
||||
unknownLbas = new List<ulong>();
|
||||
|
||||
for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
404
DiscImageChef.DiscImages/BLU/Write.cs
Normal file
404
DiscImageChef.DiscImages/BLU/Write.cs
Normal file
@@ -0,0 +1,404 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes Basic Lisa Utility disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Decoders;
|
||||
using Schemas;
|
||||
using Version = DiscImageChef.CommonTypes.Interop.Version;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Blu
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(sectorSize != 512)
|
||||
{
|
||||
ErrorMessage = "Unsupported sector size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectors > 0xFFFFFF)
|
||||
{
|
||||
ErrorMessage = "Too many sectors";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
try { writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
ErrorMessage = "Writing media tags is not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != 512)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % 512 != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress >= imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
|
||||
byte[] oldTag;
|
||||
byte[] newTag;
|
||||
|
||||
switch(data.Length - 512)
|
||||
{
|
||||
// Sony tag, convert to Profile
|
||||
case 12 when longSectorSize == 532:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Sony tag, convert to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Profile tag, copy to Profile
|
||||
case 20 when longSectorSize == 532:
|
||||
newTag = new byte[20];
|
||||
Array.Copy(data, 512, newTag, 0, 20);
|
||||
break;
|
||||
// Profile tag, convert to Priam
|
||||
case 20 when longSectorSize == 536:
|
||||
oldTag = new byte[20];
|
||||
Array.Copy(data, 512, oldTag, 0, 20);
|
||||
newTag = LisaTag.DecodeProfileTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Priam tag, convert to Profile
|
||||
case 24 when longSectorSize == 532:
|
||||
oldTag = new byte[24];
|
||||
Array.Copy(data, 512, oldTag, 0, 24);
|
||||
newTag = LisaTag.DecodePriamTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Priam tag, copy to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
newTag = new byte[24];
|
||||
Array.Copy(data, 512, newTag, 0, 24);
|
||||
break;
|
||||
case 0:
|
||||
newTag = null;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(newTag == null) newTag = new byte[longSectorSize - 512];
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, 0, 512);
|
||||
writingStream.Write(newTag, 0, newTag.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > imageInfo.Sectors)
|
||||
{
|
||||
ErrorMessage = "Tried to write past image size";
|
||||
return false;
|
||||
}
|
||||
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
long givenSectorSize = data.Length / length;
|
||||
|
||||
switch(givenSectorSize)
|
||||
{
|
||||
case 536:
|
||||
case 532:
|
||||
case 524:
|
||||
case 512: break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
byte[] oldTag;
|
||||
byte[] newTag;
|
||||
|
||||
switch(givenSectorSize - 512)
|
||||
{
|
||||
// Sony tag, convert to Profile
|
||||
case 12 when longSectorSize == 532:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Sony tag, convert to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
oldTag = new byte[12];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 12);
|
||||
newTag = LisaTag.DecodeSonyTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Profile tag, copy to Profile
|
||||
case 20 when longSectorSize == 532:
|
||||
newTag = new byte[20];
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 20);
|
||||
break;
|
||||
// Profile tag, convert to Priam
|
||||
case 20 when longSectorSize == 536:
|
||||
oldTag = new byte[20];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 20);
|
||||
newTag = LisaTag.DecodeProfileTag(oldTag)?.ToPriam().GetBytes();
|
||||
break;
|
||||
// Priam tag, convert to Profile
|
||||
case 24 when longSectorSize == 532:
|
||||
oldTag = new byte[24];
|
||||
Array.Copy(data, givenSectorSize * i + 512, oldTag, 0, 24);
|
||||
newTag = LisaTag.DecodePriamTag(oldTag)?.ToProfile().GetBytes();
|
||||
break;
|
||||
// Priam tag, copy to Priam
|
||||
case 12 when longSectorSize == 536:
|
||||
newTag = new byte[24];
|
||||
Array.Copy(data, givenSectorSize * i + 512, newTag, 0, 24);
|
||||
break;
|
||||
case 0:
|
||||
newTag = null;
|
||||
break;
|
||||
default:
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(newTag == null) newTag = new byte[longSectorSize - 512];
|
||||
|
||||
writingStream.Seek(longSectorSize + (long)sectorAddress * longSectorSize, SeekOrigin.Begin);
|
||||
writingStream.Write(data, (int)(givenSectorSize * i), 512);
|
||||
writingStream.Write(newTag, 0, newTag.Length);
|
||||
}
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
byte[] markerTag = Encoding.UTF8.GetBytes("DiscImageChef " + Version.GetVersion());
|
||||
byte[] driveName;
|
||||
byte[] driveType = new byte[3];
|
||||
byte[] driveBlocks = BigEndianBitConverter.GetBytes((uint)imageInfo.Sectors);
|
||||
int longSectorSize = imageInfo.MediaType == MediaType.PriamDataTower ? 536 : 532;
|
||||
byte[] blockSize = BigEndianBitConverter.GetBytes((ushort)longSectorSize);
|
||||
|
||||
switch(imageInfo.MediaType)
|
||||
{
|
||||
case MediaType.AppleProfile when imageInfo.Sectors == 0x4C00:
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE10_NAME);
|
||||
break;
|
||||
case MediaType.AppleWidget when imageInfo.Sectors == 0x4C00:
|
||||
driveType[1] = 0x01;
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE10_NAME);
|
||||
break;
|
||||
case MediaType.PriamDataTower when imageInfo.Sectors == 0x22C7C:
|
||||
driveType[1] = 0xFF;
|
||||
driveName = Encoding.ASCII.GetBytes(PRIAM_NAME);
|
||||
break;
|
||||
default:
|
||||
driveName = Encoding.ASCII.GetBytes(PROFILE_NAME);
|
||||
break;
|
||||
}
|
||||
|
||||
writingStream.Seek(0, SeekOrigin.Begin);
|
||||
writingStream.Write(driveName, 0, driveName.Length >= 0xD ? 0xD : driveName.Length);
|
||||
writingStream.Seek(0xD, SeekOrigin.Begin);
|
||||
writingStream.Write(driveType, 0, 3);
|
||||
writingStream.Seek(0x12, SeekOrigin.Begin);
|
||||
writingStream.Write(driveBlocks, 1, 3);
|
||||
writingStream.Seek(0x15, SeekOrigin.Begin);
|
||||
writingStream.Write(blockSize, 1, 2);
|
||||
writingStream.Seek(512, SeekOrigin.Begin);
|
||||
writingStream.Write(markerTag, 0,
|
||||
markerTag.Length >= longSectorSize - 512 ? longSectorSize - 512 : markerTag.Length);
|
||||
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
// Geometry is not stored in image
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
DiscImageChef.DiscImages/BlindWrite4/BlindWrite4.cs
Normal file
77
DiscImageChef.DiscImages/BlindWrite4/BlindWrite4.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BlindWrite4.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Too many unknowns, plus a completely unknown footer, to make this writable
|
||||
public partial class BlindWrite4 : IMediaImage
|
||||
{
|
||||
List<Bw4TrackDescriptor> bwTracks;
|
||||
IFilter dataFilter, subFilter;
|
||||
|
||||
Bw4Header header;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
Dictionary<uint, byte> trackFlags;
|
||||
|
||||
public BlindWrite4()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
44
DiscImageChef.DiscImages/BlindWrite4/Constants.cs
Normal file
44
DiscImageChef.DiscImages/BlindWrite4/Constants.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
/// <summary>"BLINDWRITE TOC FILE"</summary>
|
||||
readonly byte[] bw4Signature =
|
||||
{
|
||||
0x42, 0x4C, 0x49, 0x4E, 0x44, 0x57, 0x52, 0x49, 0x54, 0x45, 0x20, 0x54, 0x4F, 0x43, 0x20, 0x46, 0x49, 0x4C,
|
||||
0x45
|
||||
};
|
||||
}
|
||||
}
|
||||
44
DiscImageChef.DiscImages/BlindWrite4/Enums.cs
Normal file
44
DiscImageChef.DiscImages/BlindWrite4/Enums.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
enum Bw4TrackType : byte
|
||||
{
|
||||
Audio = 0,
|
||||
Mode1 = 1,
|
||||
Mode2 = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
53
DiscImageChef.DiscImages/BlindWrite4/Identify.cs
Normal file
53
DiscImageChef.DiscImages/BlindWrite4/Identify.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if(stream.Length < 19) return false;
|
||||
|
||||
byte[] signature = new byte[19];
|
||||
stream.Read(signature, 0, 19);
|
||||
|
||||
return bw4Signature.SequenceEqual(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
DiscImageChef.DiscImages/BlindWrite4/Properties.cs
Normal file
58
DiscImageChef.DiscImages/BlindWrite4/Properties.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "BlindWrite 4";
|
||||
public Guid Id => new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F");
|
||||
|
||||
public string Format => "BlindWrite 4 TOC file";
|
||||
|
||||
public List<Partition> Partitions { get; set; }
|
||||
|
||||
public List<Track> Tracks { get; set; }
|
||||
|
||||
public List<Session> Sessions { get; set; }
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// /***************************************************************************
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BlindWrite4.cs
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages BlindWrite 4 disc images.
|
||||
// Reads BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
@@ -35,7 +35,6 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.Checksums;
|
||||
using DiscImageChef.CommonTypes;
|
||||
@@ -44,79 +43,11 @@ using DiscImageChef.CommonTypes.Exceptions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using DiscImageChef.Console;
|
||||
using DiscImageChef.Filters;
|
||||
using Schemas;
|
||||
using TrackType = DiscImageChef.CommonTypes.Enums.TrackType;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Too many unknowns, plus a completely unknown footer, to make this writable
|
||||
public class BlindWrite4 : IMediaImage
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
/// <summary>"BLINDWRITE TOC FILE"</summary>
|
||||
readonly byte[] bw4Signature =
|
||||
{
|
||||
0x42, 0x4C, 0x49, 0x4E, 0x44, 0x57, 0x52, 0x49, 0x54, 0x45, 0x20, 0x54, 0x4F, 0x43, 0x20, 0x46, 0x49, 0x4C,
|
||||
0x45
|
||||
};
|
||||
List<Bw4TrackDescriptor> bwTracks;
|
||||
IFilter dataFilter, subFilter;
|
||||
|
||||
Bw4Header header;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
Dictionary<uint, byte> trackFlags;
|
||||
|
||||
public BlindWrite4()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "BlindWrite 4";
|
||||
public Guid Id => new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F");
|
||||
|
||||
public string Format => "BlindWrite 4 TOC file";
|
||||
|
||||
public List<Partition> Partitions { get; set; }
|
||||
|
||||
public List<Track> Tracks { get; set; }
|
||||
|
||||
public List<Session> Sessions { get; set; }
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if(stream.Length < 19) return false;
|
||||
|
||||
byte[] signature = new byte[19];
|
||||
stream.Read(signature, 0, 19);
|
||||
|
||||
return bw4Signature.SequenceEqual(signature);
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
@@ -1197,126 +1128,5 @@ namespace DiscImageChef.DiscImages
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
struct Bw4Header
|
||||
{
|
||||
public byte[] Signature;
|
||||
public uint Unknown1;
|
||||
public ulong Timestamp;
|
||||
public uint VolumeIdLength;
|
||||
public byte[] VolumeIdBytes;
|
||||
public uint SysIdLength;
|
||||
public byte[] SysIdBytes;
|
||||
public uint CommentsLength;
|
||||
public byte[] CommentsBytes;
|
||||
public uint TrackDescriptors;
|
||||
public uint DataFileLength;
|
||||
public byte[] DataFileBytes;
|
||||
public uint SubchannelFileLength;
|
||||
public byte[] SubchannelFileBytes;
|
||||
public uint Unknown2;
|
||||
public byte Unknown3;
|
||||
public byte[] Unknown4;
|
||||
|
||||
// On memory only
|
||||
#pragma warning disable 649
|
||||
public string VolumeIdentifier;
|
||||
public string SystemIdentifier;
|
||||
public string Comments;
|
||||
public IFilter DataFilter;
|
||||
public IFilter SubchannelFilter;
|
||||
public string DataFile;
|
||||
public string SubchannelFile;
|
||||
#pragma warning restore 649
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw4TrackDescriptor
|
||||
{
|
||||
public uint filenameLen;
|
||||
public byte[] filenameBytes;
|
||||
public uint offset;
|
||||
public byte subchannel;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] unknown1;
|
||||
public uint unknown2;
|
||||
public byte unknown3;
|
||||
public byte session;
|
||||
public byte unknown4;
|
||||
public byte adrCtl;
|
||||
public byte unknown5;
|
||||
public Bw4TrackType trackMode;
|
||||
public byte unknown6;
|
||||
public byte point;
|
||||
public uint unknown7;
|
||||
public uint unknown8;
|
||||
public uint unknown9;
|
||||
public uint unknown10;
|
||||
public ushort unknown11;
|
||||
public uint lastSector;
|
||||
public byte unknown12;
|
||||
public int pregap;
|
||||
public int startSector;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown13;
|
||||
public uint titleLen;
|
||||
public byte[] titleBytes;
|
||||
public uint performerLen;
|
||||
public byte[] performerBytes;
|
||||
public uint unkStrLen1;
|
||||
public byte[] unkStrBytes1;
|
||||
public uint unkStrLen2;
|
||||
public byte[] unkStrBytes2;
|
||||
public uint unkStrLen3;
|
||||
public byte[] unkStrBytes3;
|
||||
public uint unkStrLen4;
|
||||
public byte[] unkStrBytes4;
|
||||
public uint discIdLen;
|
||||
public byte[] discIdBytes;
|
||||
public uint unkStrLen5;
|
||||
public byte[] unkStrBytes5;
|
||||
public uint unkStrLen6;
|
||||
public byte[] unkStrBytes6;
|
||||
public uint unkStrLen7;
|
||||
public byte[] unkStrBytes7;
|
||||
public uint unkStrLen8;
|
||||
public byte[] unkStrBytes8;
|
||||
public uint unkStrLen9;
|
||||
public byte[] unkStrBytes9;
|
||||
public uint unkStrLen10;
|
||||
public byte[] unkStrBytes10;
|
||||
public uint unkStrLen11;
|
||||
public byte[] unkStrBytes11;
|
||||
public uint isrcLen;
|
||||
public byte[] isrcBytes;
|
||||
|
||||
// On memory only
|
||||
public string filename;
|
||||
public string title;
|
||||
public string performer;
|
||||
public string unkString1;
|
||||
public string unkString2;
|
||||
public string unkString3;
|
||||
public string unkString4;
|
||||
public string discId;
|
||||
public string unkString5;
|
||||
public string unkString6;
|
||||
public string unkString7;
|
||||
public string unkString8;
|
||||
public string unkString9;
|
||||
public string unkString10;
|
||||
public string unkString11;
|
||||
public string isrcUpc;
|
||||
}
|
||||
|
||||
enum Bw4TrackType : byte
|
||||
{
|
||||
Audio = 0,
|
||||
Mode1 = 1,
|
||||
Mode2 = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
151
DiscImageChef.DiscImages/BlindWrite4/Structs.cs
Normal file
151
DiscImageChef.DiscImages/BlindWrite4/Structs.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for BlindWrite 4 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite4
|
||||
{
|
||||
struct Bw4Header
|
||||
{
|
||||
public byte[] Signature;
|
||||
public uint Unknown1;
|
||||
public ulong Timestamp;
|
||||
public uint VolumeIdLength;
|
||||
public byte[] VolumeIdBytes;
|
||||
public uint SysIdLength;
|
||||
public byte[] SysIdBytes;
|
||||
public uint CommentsLength;
|
||||
public byte[] CommentsBytes;
|
||||
public uint TrackDescriptors;
|
||||
public uint DataFileLength;
|
||||
public byte[] DataFileBytes;
|
||||
public uint SubchannelFileLength;
|
||||
public byte[] SubchannelFileBytes;
|
||||
public uint Unknown2;
|
||||
public byte Unknown3;
|
||||
public byte[] Unknown4;
|
||||
|
||||
// On memory only
|
||||
#pragma warning disable 649
|
||||
public string VolumeIdentifier;
|
||||
public string SystemIdentifier;
|
||||
public string Comments;
|
||||
public IFilter DataFilter;
|
||||
public IFilter SubchannelFilter;
|
||||
public string DataFile;
|
||||
public string SubchannelFile;
|
||||
#pragma warning restore 649
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw4TrackDescriptor
|
||||
{
|
||||
public uint filenameLen;
|
||||
public byte[] filenameBytes;
|
||||
public uint offset;
|
||||
public byte subchannel;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] unknown1;
|
||||
public uint unknown2;
|
||||
public byte unknown3;
|
||||
public byte session;
|
||||
public byte unknown4;
|
||||
public byte adrCtl;
|
||||
public byte unknown5;
|
||||
public Bw4TrackType trackMode;
|
||||
public byte unknown6;
|
||||
public byte point;
|
||||
public uint unknown7;
|
||||
public uint unknown8;
|
||||
public uint unknown9;
|
||||
public uint unknown10;
|
||||
public ushort unknown11;
|
||||
public uint lastSector;
|
||||
public byte unknown12;
|
||||
public int pregap;
|
||||
public int startSector;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown13;
|
||||
public uint titleLen;
|
||||
public byte[] titleBytes;
|
||||
public uint performerLen;
|
||||
public byte[] performerBytes;
|
||||
public uint unkStrLen1;
|
||||
public byte[] unkStrBytes1;
|
||||
public uint unkStrLen2;
|
||||
public byte[] unkStrBytes2;
|
||||
public uint unkStrLen3;
|
||||
public byte[] unkStrBytes3;
|
||||
public uint unkStrLen4;
|
||||
public byte[] unkStrBytes4;
|
||||
public uint discIdLen;
|
||||
public byte[] discIdBytes;
|
||||
public uint unkStrLen5;
|
||||
public byte[] unkStrBytes5;
|
||||
public uint unkStrLen6;
|
||||
public byte[] unkStrBytes6;
|
||||
public uint unkStrLen7;
|
||||
public byte[] unkStrBytes7;
|
||||
public uint unkStrLen8;
|
||||
public byte[] unkStrBytes8;
|
||||
public uint unkStrLen9;
|
||||
public byte[] unkStrBytes9;
|
||||
public uint unkStrLen10;
|
||||
public byte[] unkStrBytes10;
|
||||
public uint unkStrLen11;
|
||||
public byte[] unkStrBytes11;
|
||||
public uint isrcLen;
|
||||
public byte[] isrcBytes;
|
||||
|
||||
// On memory only
|
||||
public string filename;
|
||||
public string title;
|
||||
public string performer;
|
||||
public string unkString1;
|
||||
public string unkString2;
|
||||
public string unkString3;
|
||||
public string unkString4;
|
||||
public string discId;
|
||||
public string unkString5;
|
||||
public string unkString6;
|
||||
public string unkString7;
|
||||
public string unkString8;
|
||||
public string unkString9;
|
||||
public string unkString10;
|
||||
public string unkString11;
|
||||
public string isrcUpc;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
DiscImageChef.DiscImages/BlindWrite5/BlindWrite5.cs
Normal file
90
DiscImageChef.DiscImages/BlindWrite5/BlindWrite5.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BlindWrite5.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Too many unknowns to make this writable
|
||||
public partial class BlindWrite5 : IMediaImage
|
||||
{
|
||||
byte[] atip;
|
||||
byte[] bca;
|
||||
List<Bw5SessionDescriptor> bwSessions;
|
||||
byte[] cdtext;
|
||||
List<Bw5DataFile> dataFiles;
|
||||
string dataPath;
|
||||
byte[] discInformation;
|
||||
byte[] dmi;
|
||||
byte[] dpm;
|
||||
List<DataFileCharacteristics> filePaths;
|
||||
byte[] fullToc;
|
||||
|
||||
Bw5Header header;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
byte[] mode2A;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
byte[] pfi;
|
||||
byte[] pma;
|
||||
Dictionary<uint, byte> trackFlags;
|
||||
byte[] unkBlock;
|
||||
|
||||
public BlindWrite5()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
44
DiscImageChef.DiscImages/BlindWrite5/Constants.cs
Normal file
44
DiscImageChef.DiscImages/BlindWrite5/Constants.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
/// <summary>"BWT5 STREAM FOOT"</summary>
|
||||
readonly byte[] bw5Footer =
|
||||
{0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x46, 0x4F, 0x4F, 0x54};
|
||||
/// <summary>"BWT5 STREAM SIGN"</summary>
|
||||
readonly byte[] bw5Signature =
|
||||
{0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x53, 0x49, 0x47, 0x4E};
|
||||
}
|
||||
}
|
||||
55
DiscImageChef.DiscImages/BlindWrite5/Enums.cs
Normal file
55
DiscImageChef.DiscImages/BlindWrite5/Enums.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
enum Bw5TrackType : byte
|
||||
{
|
||||
NotData = 0,
|
||||
Audio = 1,
|
||||
Mode1 = 2,
|
||||
Mode2 = 3,
|
||||
Mode2F1 = 4,
|
||||
Mode2F2 = 5,
|
||||
Dvd = 6
|
||||
}
|
||||
|
||||
enum Bw5TrackSubchannel : byte
|
||||
{
|
||||
None = 0,
|
||||
Q16 = 2,
|
||||
Linear = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
97
DiscImageChef.DiscImages/BlindWrite5/Helpers.cs
Normal file
97
DiscImageChef.DiscImages/BlindWrite5/Helpers.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.Decoders.SCSI.MMC;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
static TrackType BlindWriteTrackTypeToTrackType(Bw5TrackType trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case Bw5TrackType.Mode1: return TrackType.CdMode1;
|
||||
case Bw5TrackType.Mode2F1: return TrackType.CdMode2Form1;
|
||||
case Bw5TrackType.Mode2F2: return TrackType.CdMode2Form2;
|
||||
case Bw5TrackType.Mode2: return TrackType.CdMode2Formless;
|
||||
case Bw5TrackType.Audio: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static MediaType BlindWriteProfileToMediaType(ProfileNumber profile)
|
||||
{
|
||||
switch(profile)
|
||||
{
|
||||
case ProfileNumber.BDRE: return MediaType.BDRE;
|
||||
case ProfileNumber.BDROM: return MediaType.BDROM;
|
||||
case ProfileNumber.BDRRdm:
|
||||
case ProfileNumber.BDRSeq: return MediaType.BDR;
|
||||
case ProfileNumber.CDR:
|
||||
case ProfileNumber.HDBURNR: return MediaType.CDR;
|
||||
case ProfileNumber.CDROM:
|
||||
case ProfileNumber.HDBURNROM: return MediaType.CDROM;
|
||||
case ProfileNumber.CDRW:
|
||||
case ProfileNumber.HDBURNRW: return MediaType.CDRW;
|
||||
case ProfileNumber.DDCDR: return MediaType.DDCDR;
|
||||
case ProfileNumber.DDCDROM: return MediaType.DDCD;
|
||||
case ProfileNumber.DDCDRW: return MediaType.DDCDRW;
|
||||
case ProfileNumber.DVDDownload: return MediaType.DVDDownload;
|
||||
case ProfileNumber.DVDRAM: return MediaType.DVDRAM;
|
||||
case ProfileNumber.DVDRDLJump:
|
||||
case ProfileNumber.DVDRDLSeq: return MediaType.DVDRDL;
|
||||
case ProfileNumber.DVDRDLPlus: return MediaType.DVDPRDL;
|
||||
case ProfileNumber.DVDROM: return MediaType.DVDROM;
|
||||
case ProfileNumber.DVDRPlus: return MediaType.DVDPR;
|
||||
case ProfileNumber.DVDRSeq: return MediaType.DVDR;
|
||||
case ProfileNumber.DVDRWDL: return MediaType.DVDRWDL;
|
||||
case ProfileNumber.DVDRWDLPlus: return MediaType.DVDPRWDL;
|
||||
case ProfileNumber.DVDRWPlus: return MediaType.DVDPRW;
|
||||
case ProfileNumber.DVDRWRes:
|
||||
case ProfileNumber.DVDRWSeq: return MediaType.DVDRW;
|
||||
case ProfileNumber.HDDVDR: return MediaType.HDDVDR;
|
||||
case ProfileNumber.HDDVDRAM: return MediaType.HDDVDRAM;
|
||||
case ProfileNumber.HDDVDRDL: return MediaType.HDDVDRDL;
|
||||
case ProfileNumber.HDDVDROM: return MediaType.HDDVDROM;
|
||||
case ProfileNumber.HDDVDRW: return MediaType.HDDVDRW;
|
||||
case ProfileNumber.HDDVDRWDL: return MediaType.HDDVDRWDL;
|
||||
case ProfileNumber.ASMO:
|
||||
case ProfileNumber.MOErasable: return MediaType.UnknownMO;
|
||||
case ProfileNumber.NonRemovable: return MediaType.GENERIC_HDD;
|
||||
default: return MediaType.CD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
DiscImageChef.DiscImages/BlindWrite5/Identify.cs
Normal file
57
DiscImageChef.DiscImages/BlindWrite5/Identify.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if(stream.Length < 276) return false;
|
||||
|
||||
byte[] signature = new byte[16];
|
||||
stream.Read(signature, 0, 16);
|
||||
|
||||
byte[] footer = new byte[16];
|
||||
stream.Seek(-16, SeekOrigin.End);
|
||||
stream.Read(footer, 0, 16);
|
||||
|
||||
return bw5Signature.SequenceEqual(signature) && bw5Footer.SequenceEqual(footer);
|
||||
}
|
||||
}
|
||||
}
|
||||
59
DiscImageChef.DiscImages/BlindWrite5/Properties.cs
Normal file
59
DiscImageChef.DiscImages/BlindWrite5/Properties.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "BlindWrite 5";
|
||||
public Guid Id => new Guid("9CB7A381-0509-4F9F-B801-3F65434BC3EE");
|
||||
|
||||
public string Format => "BlindWrite 5 TOC file";
|
||||
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
|
||||
public List<Track> Tracks { get; private set; }
|
||||
|
||||
public List<Session> Sessions { get; private set; }
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// /***************************************************************************
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BlindWrite5.cs
|
||||
// Filename : Read.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages BlindWrite 5 disc images.
|
||||
// Reads BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
@@ -48,98 +48,13 @@ using DiscImageChef.Decoders.CD;
|
||||
using DiscImageChef.Decoders.DVD;
|
||||
using DiscImageChef.Decoders.SCSI;
|
||||
using DiscImageChef.Decoders.SCSI.MMC;
|
||||
using DiscImageChef.Filters;
|
||||
using Schemas;
|
||||
using DMI = DiscImageChef.Decoders.Xbox.DMI;
|
||||
using Session = DiscImageChef.CommonTypes.Structs.Session;
|
||||
using TrackType = DiscImageChef.CommonTypes.Enums.TrackType;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Too many unknowns to make this writable
|
||||
public class BlindWrite5 : IMediaImage
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
/// <summary>"BWT5 STREAM FOOT"</summary>
|
||||
readonly byte[] bw5Footer =
|
||||
{0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x46, 0x4F, 0x4F, 0x54};
|
||||
/// <summary>"BWT5 STREAM SIGN"</summary>
|
||||
readonly byte[] bw5Signature =
|
||||
{0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x53, 0x49, 0x47, 0x4E};
|
||||
byte[] atip;
|
||||
byte[] bca;
|
||||
List<Bw5SessionDescriptor> bwSessions;
|
||||
byte[] cdtext;
|
||||
List<Bw5DataFile> dataFiles;
|
||||
string dataPath;
|
||||
byte[] discInformation;
|
||||
byte[] dmi;
|
||||
byte[] dpm;
|
||||
List<DataFileCharacteristics> filePaths;
|
||||
byte[] fullToc;
|
||||
|
||||
Bw5Header header;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
byte[] mode2A;
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
byte[] pfi;
|
||||
byte[] pma;
|
||||
Dictionary<uint, byte> trackFlags;
|
||||
byte[] unkBlock;
|
||||
|
||||
public BlindWrite5()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
|
||||
public ImageInfo Info => imageInfo;
|
||||
|
||||
public string Name => "BlindWrite 5";
|
||||
public Guid Id => new Guid("9CB7A381-0509-4F9F-B801-3F65434BC3EE");
|
||||
|
||||
public string Format => "BlindWrite 5 TOC file";
|
||||
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
|
||||
public List<Track> Tracks { get; private set; }
|
||||
|
||||
public List<Session> Sessions { get; private set; }
|
||||
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if(stream.Length < 276) return false;
|
||||
|
||||
byte[] signature = new byte[16];
|
||||
stream.Read(signature, 0, 16);
|
||||
|
||||
byte[] footer = new byte[16];
|
||||
stream.Seek(-16, SeekOrigin.End);
|
||||
stream.Read(footer, 0, 16);
|
||||
|
||||
return bw5Signature.SequenceEqual(signature) && bw5Footer.SequenceEqual(footer);
|
||||
}
|
||||
|
||||
public bool Open(IFilter imageFilter)
|
||||
{
|
||||
Stream stream = imageFilter.GetDataForkStream();
|
||||
@@ -1761,203 +1676,5 @@ namespace DiscImageChef.DiscImages
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
|
||||
static TrackType BlindWriteTrackTypeToTrackType(Bw5TrackType trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case Bw5TrackType.Mode1: return TrackType.CdMode1;
|
||||
case Bw5TrackType.Mode2F1: return TrackType.CdMode2Form1;
|
||||
case Bw5TrackType.Mode2F2: return TrackType.CdMode2Form2;
|
||||
case Bw5TrackType.Mode2: return TrackType.CdMode2Formless;
|
||||
case Bw5TrackType.Audio: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static MediaType BlindWriteProfileToMediaType(ProfileNumber profile)
|
||||
{
|
||||
switch(profile)
|
||||
{
|
||||
case ProfileNumber.BDRE: return MediaType.BDRE;
|
||||
case ProfileNumber.BDROM: return MediaType.BDROM;
|
||||
case ProfileNumber.BDRRdm:
|
||||
case ProfileNumber.BDRSeq: return MediaType.BDR;
|
||||
case ProfileNumber.CDR:
|
||||
case ProfileNumber.HDBURNR: return MediaType.CDR;
|
||||
case ProfileNumber.CDROM:
|
||||
case ProfileNumber.HDBURNROM: return MediaType.CDROM;
|
||||
case ProfileNumber.CDRW:
|
||||
case ProfileNumber.HDBURNRW: return MediaType.CDRW;
|
||||
case ProfileNumber.DDCDR: return MediaType.DDCDR;
|
||||
case ProfileNumber.DDCDROM: return MediaType.DDCD;
|
||||
case ProfileNumber.DDCDRW: return MediaType.DDCDRW;
|
||||
case ProfileNumber.DVDDownload: return MediaType.DVDDownload;
|
||||
case ProfileNumber.DVDRAM: return MediaType.DVDRAM;
|
||||
case ProfileNumber.DVDRDLJump:
|
||||
case ProfileNumber.DVDRDLSeq: return MediaType.DVDRDL;
|
||||
case ProfileNumber.DVDRDLPlus: return MediaType.DVDPRDL;
|
||||
case ProfileNumber.DVDROM: return MediaType.DVDROM;
|
||||
case ProfileNumber.DVDRPlus: return MediaType.DVDPR;
|
||||
case ProfileNumber.DVDRSeq: return MediaType.DVDR;
|
||||
case ProfileNumber.DVDRWDL: return MediaType.DVDRWDL;
|
||||
case ProfileNumber.DVDRWDLPlus: return MediaType.DVDPRWDL;
|
||||
case ProfileNumber.DVDRWPlus: return MediaType.DVDPRW;
|
||||
case ProfileNumber.DVDRWRes:
|
||||
case ProfileNumber.DVDRWSeq: return MediaType.DVDRW;
|
||||
case ProfileNumber.HDDVDR: return MediaType.HDDVDR;
|
||||
case ProfileNumber.HDDVDRAM: return MediaType.HDDVDRAM;
|
||||
case ProfileNumber.HDDVDRDL: return MediaType.HDDVDRDL;
|
||||
case ProfileNumber.HDDVDROM: return MediaType.HDDVDROM;
|
||||
case ProfileNumber.HDDVDRW: return MediaType.HDDVDRW;
|
||||
case ProfileNumber.HDDVDRWDL: return MediaType.HDDVDRWDL;
|
||||
case ProfileNumber.ASMO:
|
||||
case ProfileNumber.MOErasable: return MediaType.UnknownMO;
|
||||
case ProfileNumber.NonRemovable: return MediaType.GENERIC_HDD;
|
||||
default: return MediaType.CD;
|
||||
}
|
||||
}
|
||||
|
||||
enum Bw5TrackType : byte
|
||||
{
|
||||
NotData = 0,
|
||||
Audio = 1,
|
||||
Mode1 = 2,
|
||||
Mode2 = 3,
|
||||
Mode2F1 = 4,
|
||||
Mode2F2 = 5,
|
||||
Dvd = 6
|
||||
}
|
||||
|
||||
enum Bw5TrackSubchannel : byte
|
||||
{
|
||||
None = 0,
|
||||
Q16 = 2,
|
||||
Linear = 4
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] signature;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public uint[] unknown1;
|
||||
public ProfileNumber profile;
|
||||
public ushort sessions;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown2;
|
||||
[MarshalAs(UnmanagedType.U1, SizeConst = 3)]
|
||||
public bool mcnIsValid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
|
||||
public byte[] mcn;
|
||||
public ushort unknown3;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public uint[] unknown4;
|
||||
public ushort pmaLen;
|
||||
public ushort atipLen;
|
||||
public ushort cdtLen;
|
||||
public ushort cdInfoLen;
|
||||
public uint bcaLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown5;
|
||||
public uint dvdStrLen;
|
||||
public uint dvdInfoLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] unknown6;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] manufacturer;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] product;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[] revision;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
|
||||
public byte[] vendor;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] volumeId;
|
||||
public uint mode2ALen;
|
||||
public uint unkBlkLen;
|
||||
public uint dataLen;
|
||||
public uint sessionsLen;
|
||||
public uint dpmLen;
|
||||
}
|
||||
|
||||
struct Bw5DataFile
|
||||
{
|
||||
public uint Type;
|
||||
public uint Length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] Unknown1;
|
||||
public uint Offset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] Unknown2;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint FilenameLen;
|
||||
public byte[] FilenameBytes;
|
||||
public uint Unknown3;
|
||||
|
||||
public string Filename;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5TrackDescriptor
|
||||
{
|
||||
public Bw5TrackType type;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] unknown1;
|
||||
public uint unknown2;
|
||||
public Bw5TrackSubchannel subchannel;
|
||||
public byte unknown3;
|
||||
public byte ctl;
|
||||
public byte adr;
|
||||
public byte point;
|
||||
public byte tno;
|
||||
public byte min;
|
||||
public byte sec;
|
||||
public byte frame;
|
||||
public byte zero;
|
||||
public byte pmin;
|
||||
public byte psec;
|
||||
public byte pframe;
|
||||
public byte unknown5;
|
||||
public uint pregap;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public uint[] unknown6;
|
||||
public int startLba;
|
||||
public int sectors;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown7;
|
||||
public uint session;
|
||||
public ushort unknown8;
|
||||
// Seems to be only on non DVD track descriptors
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown9;
|
||||
}
|
||||
|
||||
struct Bw5SessionDescriptor
|
||||
{
|
||||
public ushort Sequence;
|
||||
public byte Entries;
|
||||
public byte Unknown;
|
||||
public int Start;
|
||||
public int End;
|
||||
public ushort FirstTrack;
|
||||
public ushort LastTrack;
|
||||
public Bw5TrackDescriptor[] Tracks;
|
||||
}
|
||||
|
||||
struct DataFileCharacteristics
|
||||
{
|
||||
public IFilter FileFilter;
|
||||
public string FilePath;
|
||||
public TrackSubchannelType Subchannel;
|
||||
public long SectorSize;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
166
DiscImageChef.DiscImages/BlindWrite5/Structs.cs
Normal file
166
DiscImageChef.DiscImages/BlindWrite5/Structs.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for BlindWrite 5 disc images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Decoders.SCSI.MMC;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class BlindWrite5
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] signature;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public uint[] unknown1;
|
||||
public ProfileNumber profile;
|
||||
public ushort sessions;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown2;
|
||||
[MarshalAs(UnmanagedType.U1, SizeConst = 3)]
|
||||
public bool mcnIsValid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
|
||||
public byte[] mcn;
|
||||
public ushort unknown3;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public uint[] unknown4;
|
||||
public ushort pmaLen;
|
||||
public ushort atipLen;
|
||||
public ushort cdtLen;
|
||||
public ushort cdInfoLen;
|
||||
public uint bcaLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown5;
|
||||
public uint dvdStrLen;
|
||||
public uint dvdInfoLen;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] unknown6;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] manufacturer;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public byte[] product;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[] revision;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
|
||||
public byte[] vendor;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||
public byte[] volumeId;
|
||||
public uint mode2ALen;
|
||||
public uint unkBlkLen;
|
||||
public uint dataLen;
|
||||
public uint sessionsLen;
|
||||
public uint dpmLen;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5DataFile
|
||||
{
|
||||
public uint Type;
|
||||
public uint Length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] Unknown1;
|
||||
public uint Offset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] Unknown2;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
public uint FilenameLen;
|
||||
public byte[] FilenameBytes;
|
||||
public uint Unknown3;
|
||||
|
||||
public string Filename;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5TrackDescriptor
|
||||
{
|
||||
public Bw5TrackType type;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] unknown1;
|
||||
public uint unknown2;
|
||||
public Bw5TrackSubchannel subchannel;
|
||||
public byte unknown3;
|
||||
public byte ctl;
|
||||
public byte adr;
|
||||
public byte point;
|
||||
public byte tno;
|
||||
public byte min;
|
||||
public byte sec;
|
||||
public byte frame;
|
||||
public byte zero;
|
||||
public byte pmin;
|
||||
public byte psec;
|
||||
public byte pframe;
|
||||
public byte unknown5;
|
||||
public uint pregap;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public uint[] unknown6;
|
||||
public int startLba;
|
||||
public int sectors;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown7;
|
||||
public uint session;
|
||||
public ushort unknown8;
|
||||
// Seems to be only on non DVD track descriptors
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown9;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Bw5SessionDescriptor
|
||||
{
|
||||
public ushort Sequence;
|
||||
public byte Entries;
|
||||
public byte Unknown;
|
||||
public int Start;
|
||||
public int End;
|
||||
public ushort FirstTrack;
|
||||
public ushort LastTrack;
|
||||
public Bw5TrackDescriptor[] Tracks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DataFileCharacteristics
|
||||
{
|
||||
public IFilter FileFilter;
|
||||
public string FilePath;
|
||||
public TrackSubchannelType Subchannel;
|
||||
public long SectorSize;
|
||||
public int StartLba;
|
||||
public int Sectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
84
DiscImageChef.DiscImages/CDRDAO/CDRDAO.cs
Normal file
84
DiscImageChef.DiscImages/CDRDAO/CDRDAO.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CDRDAO.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Doesn't support compositing from several files
|
||||
// TODO: Doesn't support silences that are not in files
|
||||
public partial class Cdrdao : IWritableImage
|
||||
{
|
||||
IFilter cdrdaoFilter;
|
||||
StreamWriter descriptorStream;
|
||||
CdrdaoDisc discimage;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
/// <summary>Dictionary, index is track #, value is TrackFile</summary>
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
bool separateTracksWriting;
|
||||
StreamReader tocStream;
|
||||
Dictionary<byte, byte> trackFlags;
|
||||
Dictionary<byte, string> trackIsrcs;
|
||||
string writingBaseName;
|
||||
Dictionary<uint, FileStream> writingStreams;
|
||||
List<Track> writingTracks;
|
||||
|
||||
public Cdrdao()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
90
DiscImageChef.DiscImages/CDRDAO/Constants.cs
Normal file
90
DiscImageChef.DiscImages/CDRDAO/Constants.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
/// <summary>Audio track, 2352 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_AUDIO = "AUDIO";
|
||||
/// <summary>Mode 1 track, cooked, 2048 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE1 = "MODE1";
|
||||
/// <summary>Mode 1 track, raw, 2352 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE1_RAW = "MODE1_RAW";
|
||||
/// <summary>Mode 2 mixed formless, cooked, 2336 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE2 = "MODE2";
|
||||
/// <summary>Mode 2 form 1 track, cooked, 2048 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE2_FORM1 = "MODE2_FORM1";
|
||||
/// <summary>Mode 2 form 2 track, cooked, 2324 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE2_FORM2 = "MODE2_FORM2";
|
||||
/// <summary>Mode 2 mixed forms track, cooked, 2336 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE2_MIX = "MODE2_FORM_MIX";
|
||||
/// <summary>Mode 2 track, raw, 2352 bytes/sector</summary>
|
||||
const string CDRDAO_TRACK_TYPE_MODE2_RAW = "MODE2_RAW";
|
||||
|
||||
const string REGEX_COMMENT = @"^\s*\/{2}(?<comment>.+)$";
|
||||
const string REGEX_COPY = @"^\s*(?<no>NO)?\s*COPY";
|
||||
const string REGEX_DISCTYPE = @"^\s*(?<type>(CD_DA|CD_ROM_XA|CD_ROM|CD_I))";
|
||||
const string REGEX_EMPHASIS = @"^\s*(?<no>NO)?\s*PRE_EMPHASIS";
|
||||
const string REGEX_FILE_AUDIO =
|
||||
@"^\s*(AUDIO)?FILE\s*""(?<filename>.+)""\s*(#(?<base_offset>\d+))?\s*((?<start>[\d]+:[\d]+:[\d]+)|(?<start_num>\d+))\s*(?<length>[\d]+:[\d]+:[\d]+)?";
|
||||
const string REGEX_FILE_DATA =
|
||||
@"^\s*DATAFILE\s*""(?<filename>.+)""\s*(#(?<base_offset>\d+))?\s*(?<length>[\d]+:[\d]+:[\d]+)?";
|
||||
const string REGEX_INDEX = @"^\s*INDEX\s*(?<address>\d+:\d+:\d+)";
|
||||
const string REGEX_ISRC = @"^\s*ISRC\s*""(?<isrc>[A-Z0-9]{5,5}[0-9]{7,7})""";
|
||||
const string REGEX_MCN = @"^\s*CATALOG\s*""(?<catalog>[\x21-\x7F]{13,13})""";
|
||||
const string REGEX_PREGAP = @"^\s*START\s*(?<address>\d+:\d+:\d+)?";
|
||||
const string REGEX_STEREO = @"^\s*(?<num>(TWO|FOUR))_CHANNEL_AUDIO";
|
||||
const string REGEX_TRACK =
|
||||
@"^\s*TRACK\s*(?<type>(AUDIO|MODE1_RAW|MODE1|MODE2_FORM1|MODE2_FORM2|MODE2_FORM_MIX|MODE2_RAW|MODE2))\s*(?<subchan>(RW_RAW|RW))?";
|
||||
const string REGEX_ZERO_AUDIO = @"^\s*SILENCE\s*(?<length>\d+:\d+:\d+)";
|
||||
const string REGEX_ZERO_DATA = @"^\s*ZERO\s*(?<length>\d+:\d+:\d+)";
|
||||
const string REGEX_ZERO_PREGAP = @"^\s*PREGAP\s*(?<length>\d+:\d+:\d+)";
|
||||
|
||||
// CD-Text
|
||||
const string REGEX_ARRANGER = @"^\s*ARRANGER\s*""(?<arranger>.+)""";
|
||||
const string REGEX_COMPOSER = @"^\s*COMPOSER\s*""(?<composer>.+)""";
|
||||
const string REGEX_DISC_ID = @"^\s*DISC_ID\s*""(?<discid>.+)""";
|
||||
const string REGEX_MESSAGE = @"^\s*MESSAGE\s*""(?<message>.+)""";
|
||||
const string REGEX_PERFORMER = @"^\s*PERFORMER\s*""(?<performer>.+)""";
|
||||
const string REGEX_SONGWRITER = @"^\s*SONGWRITER\s*""(?<songwriter>.+)""";
|
||||
const string REGEX_TITLE = @"^\s*TITLE\s*""(?<title>.+)""";
|
||||
const string REGEX_UPC = @"^\s*UPC_EAN\s*""(?<catalog>[\d]{13,13})""";
|
||||
|
||||
// Unused
|
||||
const string REGEX_CD_TEXT = @"^\s*CD_TEXT\s*\{";
|
||||
const string REGEX_CLOSURE = @"^\s*\}";
|
||||
const string REGEX_LANGUAGE = @"^\s*LANGUAGE\s*(?<code>\d+)\s*\{";
|
||||
const string REGEX_LANGUAGE_MAP = @"^\s*LANGUAGE_MAP\s*\{";
|
||||
const string REGEX_LANGUAGE_MAPPING = @"^\s*(?<code>\d+)\s?\:\s?(?<language>\d+|\w+)";
|
||||
}
|
||||
}
|
||||
114
DiscImageChef.DiscImages/CDRDAO/Helpers.cs
Normal file
114
DiscImageChef.DiscImages/CDRDAO/Helpers.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
static ushort CdrdaoTrackTypeToBytesPerSector(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRDAO_TRACK_TYPE_MODE1:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM1: return 2048;
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM2: return 2324;
|
||||
case CDRDAO_TRACK_TYPE_MODE2:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_MIX: return 2336;
|
||||
case CDRDAO_TRACK_TYPE_AUDIO:
|
||||
case CDRDAO_TRACK_TYPE_MODE1_RAW:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_RAW: return 2352;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ushort CdrdaoTrackTypeToCookedBytesPerSector(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRDAO_TRACK_TYPE_MODE1:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM1:
|
||||
case CDRDAO_TRACK_TYPE_MODE1_RAW: return 2048;
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM2: return 2324;
|
||||
case CDRDAO_TRACK_TYPE_MODE2:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_MIX:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_RAW: return 2336;
|
||||
case CDRDAO_TRACK_TYPE_AUDIO: return 2352;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static TrackType CdrdaoTrackTypeToTrackType(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRDAO_TRACK_TYPE_MODE1:
|
||||
case CDRDAO_TRACK_TYPE_MODE1_RAW: return TrackType.CdMode1;
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM1: return TrackType.CdMode2Form1;
|
||||
case CDRDAO_TRACK_TYPE_MODE2_FORM2: return TrackType.CdMode2Form2;
|
||||
case CDRDAO_TRACK_TYPE_MODE2:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_MIX:
|
||||
case CDRDAO_TRACK_TYPE_MODE2_RAW: return TrackType.CdMode2Formless;
|
||||
case CDRDAO_TRACK_TYPE_AUDIO: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector)
|
||||
{
|
||||
return ((byte)(sector / 75 / 60), (byte)(sector / 75 % 60), (byte)(sector % 75));
|
||||
}
|
||||
|
||||
static string GetTrackMode(Track track)
|
||||
{
|
||||
switch(track.TrackType)
|
||||
{
|
||||
case TrackType.Audio when track.TrackRawBytesPerSector == 2352: return CDRDAO_TRACK_TYPE_AUDIO;
|
||||
case TrackType.Data: return CDRDAO_TRACK_TYPE_MODE1;
|
||||
case TrackType.CdMode1 when track.TrackRawBytesPerSector == 2352: return CDRDAO_TRACK_TYPE_MODE1_RAW;
|
||||
case TrackType.CdMode2Formless
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRDAO_TRACK_TYPE_MODE2;
|
||||
case TrackType.CdMode2Form1
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRDAO_TRACK_TYPE_MODE2_FORM1;
|
||||
case TrackType.CdMode2Form2
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRDAO_TRACK_TYPE_MODE2_FORM2;
|
||||
case TrackType.CdMode2Formless when track.TrackRawBytesPerSector == 2352:
|
||||
case TrackType.CdMode2Form1 when track.TrackRawBytesPerSector == 2352:
|
||||
case TrackType.CdMode2Form2
|
||||
when track.TrackRawBytesPerSector == 2352: return CDRDAO_TRACK_TYPE_MODE2_RAW;
|
||||
default: return CDRDAO_TRACK_TYPE_MODE1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
DiscImageChef.DiscImages/CDRDAO/Identify.cs
Normal file
98
DiscImageChef.DiscImages/CDRDAO/Identify.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
try
|
||||
{
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
byte[] testArray = new byte[512];
|
||||
imageFilter.GetDataForkStream().Read(testArray, 0, 512);
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
// Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin
|
||||
bool twoConsecutiveNulls = false;
|
||||
for(int i = 0; i < 512; i++)
|
||||
{
|
||||
if(i >= imageFilter.GetDataForkStream().Length) break;
|
||||
|
||||
if(testArray[i] == 0)
|
||||
{
|
||||
if(twoConsecutiveNulls) return false;
|
||||
|
||||
twoConsecutiveNulls = true;
|
||||
}
|
||||
else twoConsecutiveNulls = false;
|
||||
|
||||
if(testArray[i] < 0x20 && testArray[i] != 0x0A && testArray[i] != 0x0D && testArray[i] != 0x00)
|
||||
return false;
|
||||
}
|
||||
|
||||
tocStream = new StreamReader(imageFilter.GetDataForkStream());
|
||||
|
||||
Regex cr = new Regex(REGEX_COMMENT);
|
||||
Regex dr = new Regex(REGEX_DISCTYPE);
|
||||
|
||||
while(tocStream.Peek() >= 0)
|
||||
{
|
||||
string line = tocStream.ReadLine();
|
||||
|
||||
Match dm = dr.Match(line ?? throw new InvalidOperationException());
|
||||
Match cm = cr.Match(line);
|
||||
|
||||
// Skip comments at start of file
|
||||
if(cm.Success) continue;
|
||||
|
||||
return dm.Success;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", cdrdaoFilter.GetFilename());
|
||||
DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
|
||||
DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
124
DiscImageChef.DiscImages/CDRDAO/Properties.cs
Normal file
124
DiscImageChef.DiscImages/CDRDAO/Properties.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
public string Name => "CDRDAO tocfile";
|
||||
public Guid Id => new Guid("04D7BA12-1BE8-44D4-97A4-1B48A505463E");
|
||||
public string Format => "CDRDAO tocfile";
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
public List<Session> Sessions => throw new NotImplementedException();
|
||||
|
||||
public List<Track> Tracks
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Track> tracks = new List<Track>();
|
||||
|
||||
foreach(CdrdaoTrack cdrTrack in discimage.Tracks)
|
||||
{
|
||||
Track dicTrack = new Track
|
||||
{
|
||||
Indexes = cdrTrack.Indexes,
|
||||
TrackDescription = cdrTrack.Title,
|
||||
TrackStartSector = cdrTrack.StartSector,
|
||||
TrackPregap = cdrTrack.Pregap,
|
||||
TrackSession = 1,
|
||||
TrackSequence = cdrTrack.Sequence,
|
||||
TrackType = CdrdaoTrackTypeToTrackType(cdrTrack.Tracktype),
|
||||
TrackFilter = cdrTrack.Trackfile.Datafilter,
|
||||
TrackFile = cdrTrack.Trackfile.Datafilter.GetFilename(),
|
||||
TrackFileOffset = cdrTrack.Trackfile.Offset,
|
||||
TrackFileType = cdrTrack.Trackfile.Filetype,
|
||||
TrackRawBytesPerSector = cdrTrack.Bps,
|
||||
TrackBytesPerSector = CdrdaoTrackTypeToCookedBytesPerSector(cdrTrack.Tracktype)
|
||||
};
|
||||
|
||||
dicTrack.TrackEndSector = dicTrack.TrackStartSector + cdrTrack.Sectors - 1;
|
||||
if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector))
|
||||
cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);
|
||||
if(cdrTrack.Subchannel)
|
||||
{
|
||||
dicTrack.TrackSubchannelType = cdrTrack.Packedsubchannel
|
||||
? TrackSubchannelType.PackedInterleaved
|
||||
: TrackSubchannelType.RawInterleaved;
|
||||
dicTrack.TrackSubchannelFilter = cdrTrack.Trackfile.Datafilter;
|
||||
dicTrack.TrackSubchannelFile = cdrTrack.Trackfile.Datafilter.GetFilename();
|
||||
dicTrack.TrackSubchannelOffset = cdrTrack.Trackfile.Offset;
|
||||
}
|
||||
else dicTrack.TrackSubchannelType = TrackSubchannelType.None;
|
||||
|
||||
tracks.Add(dicTrack);
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
}
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
// TODO: Decode CD-Text to text
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new[] {MediaTagType.CD_MCN};
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags =>
|
||||
new[]
|
||||
{
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
|
||||
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubchannel,
|
||||
SectorTagType.CdSectorSubHeader, SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags,
|
||||
SectorTagType.CdTrackIsrc
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
|
||||
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
|
||||
MediaType.CDV, MediaType.DDCD, MediaType.DDCDR, MediaType.DDCDRW, MediaType.JaguarCD, MediaType.MEGACD,
|
||||
MediaType.PD650, MediaType.PD650_WORM, MediaType.PS1CD, MediaType.PS2CD, MediaType.SuperCDROM2,
|
||||
MediaType.SVCD, MediaType.SATURNCD, MediaType.ThreeDO, MediaType.VCD, MediaType.VCDHD,
|
||||
MediaType.NeoGeoCD, MediaType.PCFX
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new[] {("separate", typeof(bool), "Write each track to a separate file.")};
|
||||
public IEnumerable<string> KnownExtensions => new[] {".toc"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
139
DiscImageChef.DiscImages/CDRDAO/Structs.cs
Normal file
139
DiscImageChef.DiscImages/CDRDAO/Structs.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
struct CdrdaoTrackFile
|
||||
{
|
||||
/// <summary>Track #</summary>
|
||||
public uint Sequence;
|
||||
/// <summary>Filter of file containing track</summary>
|
||||
public IFilter Datafilter;
|
||||
/// <summary>Path of file containing track</summary>
|
||||
public string Datafile;
|
||||
/// <summary>Offset of track start in file</summary>
|
||||
public ulong Offset;
|
||||
/// <summary>Type of file</summary>
|
||||
public string Filetype;
|
||||
}
|
||||
|
||||
#pragma warning disable 169
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
struct CdrdaoTrack
|
||||
{
|
||||
/// <summary>Track #</summary>
|
||||
public uint Sequence;
|
||||
/// <summary>Track title (from CD-Text)</summary>
|
||||
public string Title;
|
||||
/// <summary>Track genre (from CD-Text)</summary>
|
||||
public string Genre;
|
||||
/// <summary>Track arranger (from CD-Text)</summary>
|
||||
public string Arranger;
|
||||
/// <summary>Track composer (from CD-Text)</summary>
|
||||
public string Composer;
|
||||
/// <summary>Track performer (from CD-Text)</summary>
|
||||
public string Performer;
|
||||
/// <summary>Track song writer (from CD-Text)</summary>
|
||||
public string Songwriter;
|
||||
/// <summary>Track ISRC</summary>
|
||||
public string Isrc;
|
||||
/// <summary>Disk provider's message (from CD-Text)</summary>
|
||||
public string Message;
|
||||
/// <summary>File struct for this track</summary>
|
||||
public CdrdaoTrackFile Trackfile;
|
||||
/// <summary>Indexes on this track</summary>
|
||||
public Dictionary<int, ulong> Indexes;
|
||||
/// <summary>Track pre-gap in sectors</summary>
|
||||
public ulong Pregap;
|
||||
/// <summary>Track post-gap in sectors</summary>
|
||||
public ulong Postgap;
|
||||
/// <summary>Digical Copy Permitted</summary>
|
||||
public bool FlagDcp;
|
||||
/// <summary>Track is quadraphonic</summary>
|
||||
public bool Flag_4Ch;
|
||||
/// <summary>Track has preemphasis</summary>
|
||||
public bool FlagPre;
|
||||
/// <summary>Bytes per sector</summary>
|
||||
public ushort Bps;
|
||||
/// <summary>Sectors in track</summary>
|
||||
public ulong Sectors;
|
||||
/// <summary>Starting sector in track</summary>
|
||||
public ulong StartSector;
|
||||
/// <summary>Track type</summary>
|
||||
public string Tracktype;
|
||||
public bool Subchannel;
|
||||
public bool Packedsubchannel;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
struct CdrdaoDisc
|
||||
{
|
||||
/// <summary>Disk title (from CD-Text)</summary>
|
||||
public string Title;
|
||||
/// <summary>Disk genre (from CD-Text)</summary>
|
||||
public string Genre;
|
||||
/// <summary>Disk arranger (from CD-Text)</summary>
|
||||
public string Arranger;
|
||||
/// <summary>Disk composer (from CD-Text)</summary>
|
||||
public string Composer;
|
||||
/// <summary>Disk performer (from CD-Text)</summary>
|
||||
public string Performer;
|
||||
/// <summary>Disk song writer (from CD-Text)</summary>
|
||||
public string Songwriter;
|
||||
/// <summary>Disk provider's message (from CD-Text)</summary>
|
||||
public string Message;
|
||||
/// <summary>Media catalog number</summary>
|
||||
public string Mcn;
|
||||
/// <summary>Disk type</summary>
|
||||
public MediaType Disktype;
|
||||
/// <summary>Disk type string</summary>
|
||||
public string Disktypestr;
|
||||
/// <summary>Disk CDDB ID</summary>
|
||||
public string DiskId;
|
||||
/// <summary>Disk UPC/EAN</summary>
|
||||
public string Barcode;
|
||||
/// <summary>Tracks</summary>
|
||||
public List<CdrdaoTrack> Tracks;
|
||||
/// <summary>Disk comment</summary>
|
||||
public string Comment;
|
||||
}
|
||||
#pragma warning restore 169
|
||||
}
|
||||
}
|
||||
42
DiscImageChef.DiscImages/CDRDAO/Unsupported.cs
Normal file
42
DiscImageChef.DiscImages/CDRDAO/Unsupported.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
698
DiscImageChef.DiscImages/CDRDAO/Write.cs
Normal file
698
DiscImageChef.DiscImages/CDRDAO/Write.cs
Normal file
@@ -0,0 +1,698 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes cdrdao cuesheets (toc/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
using TrackType = DiscImageChef.CommonTypes.Enums.TrackType;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Cdrdao
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(options != null)
|
||||
{
|
||||
if(options.TryGetValue("separate", out string tmpValue))
|
||||
{
|
||||
if(!bool.TryParse(tmpValue, out separateTracksWriting))
|
||||
{
|
||||
ErrorMessage = "Invalid value for split option";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(separateTracksWriting)
|
||||
{
|
||||
ErrorMessage = "Separate tracksnot yet implemented";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else separateTracksWriting = false;
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
// TODO: Separate tracks
|
||||
try
|
||||
{
|
||||
writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
|
||||
descriptorStream = new StreamWriter(path, false, Encoding.ASCII);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
discimage = new CdrdaoDisc {Disktype = mediaType, Tracks = new List<CdrdaoTrack>()};
|
||||
|
||||
trackFlags = new Dictionary<byte, byte>();
|
||||
trackIsrcs = new Dictionary<byte, string>();
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case MediaTagType.CD_MCN:
|
||||
discimage.Mcn = Encoding.ASCII.GetString(data);
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported media tag {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// cdrdao audio tracks are endian swapped corresponding to DiscImageChef
|
||||
if(track.TrackType == TrackType.Audio)
|
||||
{
|
||||
byte[] swapped = new byte[data.Length];
|
||||
for(long i = 0; i < swapped.Length; i += 2)
|
||||
{
|
||||
swapped[i] = data[i + 1];
|
||||
swapped[i + 1] = data[i];
|
||||
}
|
||||
|
||||
data = swapped;
|
||||
}
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// cdrdao audio tracks are endian swapped corresponding to DiscImageChef
|
||||
if(track.TrackType == TrackType.Audio)
|
||||
{
|
||||
byte[] swapped = new byte[data.Length];
|
||||
for(long i = 0; i < swapped.Length; i += 2)
|
||||
{
|
||||
swapped[i] = data[i + 1];
|
||||
swapped[i + 1] = data[i];
|
||||
}
|
||||
|
||||
data = swapped;
|
||||
}
|
||||
|
||||
switch(track.TrackSubchannelType)
|
||||
{
|
||||
case TrackSubchannelType.None:
|
||||
trackStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
trackStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)),
|
||||
SeekOrigin.Begin);
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
trackStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector);
|
||||
trackStream.Position += 96;
|
||||
}
|
||||
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = "Invalid subchannel mode for this sector";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// cdrdao audio tracks are endian swapped corresponding to DiscImageChef
|
||||
if(track.TrackType == TrackType.Audio)
|
||||
{
|
||||
byte[] swapped = new byte[data.Length];
|
||||
for(long i = 0; i < swapped.Length; i += 2)
|
||||
{
|
||||
swapped[i] = data[i + 1];
|
||||
swapped[i + 1] = data[i];
|
||||
}
|
||||
|
||||
data = swapped;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// cdrdao audio tracks are endian swapped corresponding to DiscImageChef
|
||||
if(track.TrackType == TrackType.Audio)
|
||||
{
|
||||
byte[] swapped = new byte[data.Length];
|
||||
for(long i = 0; i < swapped.Length; i += 2)
|
||||
{
|
||||
swapped[i] = data[i + 1];
|
||||
swapped[i + 1] = data[i];
|
||||
}
|
||||
|
||||
data = swapped;
|
||||
}
|
||||
|
||||
uint subchannelSize = (uint)(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0);
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (i + sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + subchannelSize)),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, (int)(i * track.TrackRawBytesPerSector), track.TrackRawBytesPerSector);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tracks == null || tracks.Count == 0)
|
||||
{
|
||||
ErrorMessage = "Invalid tracks sent";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(writingTracks != null && writingStreams != null)
|
||||
foreach(FileStream oldTrack in writingStreams.Select(t => t.Value).Distinct())
|
||||
oldTrack.Close();
|
||||
|
||||
ulong currentOffset = 0;
|
||||
writingTracks = new List<Track>();
|
||||
foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
|
||||
{
|
||||
if(track.TrackSubchannelType == TrackSubchannelType.Q16 ||
|
||||
track.TrackSubchannelType == TrackSubchannelType.Q16Interleaved)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Unsupported subchannel type {track.TrackSubchannelType} for track {track.TrackSequence}";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track newTrack = track;
|
||||
newTrack.TrackFile = separateTracksWriting
|
||||
? writingBaseName + $"_track{track.TrackSequence:D2}.bin"
|
||||
: writingBaseName + ".bin";
|
||||
newTrack.TrackFileOffset = separateTracksWriting ? 0 : currentOffset;
|
||||
writingTracks.Add(newTrack);
|
||||
currentOffset += (ulong)newTrack.TrackRawBytesPerSector *
|
||||
(newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
|
||||
if(track.TrackSubchannelType != TrackSubchannelType.None)
|
||||
currentOffset += 96 * (newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
}
|
||||
|
||||
writingStreams = new Dictionary<uint, FileStream>();
|
||||
if(separateTracksWriting)
|
||||
foreach(Track track in writingTracks)
|
||||
writingStreams.Add(track.TrackSequence,
|
||||
new FileStream(track.TrackFile, FileMode.OpenOrCreate, FileAccess.ReadWrite,
|
||||
FileShare.None));
|
||||
else
|
||||
{
|
||||
FileStream jointstream = new FileStream(writingBaseName + ".bin", FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite, FileShare.None);
|
||||
foreach(Track track in writingTracks) writingStreams.Add(track.TrackSequence, jointstream);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(separateTracksWriting)
|
||||
foreach(FileStream writingStream in writingStreams.Values)
|
||||
{
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
writingStreams.First().Value.Flush();
|
||||
writingStreams.First().Value.Close();
|
||||
}
|
||||
|
||||
bool data = writingTracks.Count(t => t.TrackType != TrackType.Audio) > 0;
|
||||
bool mode2 = writingTracks.Count(t => t.TrackType == TrackType.CdMode2Form1 ||
|
||||
t.TrackType == TrackType.CdMode2Form2 ||
|
||||
t.TrackType == TrackType.CdMode2Formless) > 0;
|
||||
|
||||
if(mode2) descriptorStream.WriteLine("CD_ROM_XA");
|
||||
else if(data) descriptorStream.WriteLine("CD_ROM");
|
||||
else descriptorStream.WriteLine("CD_DA");
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(discimage.Comment))
|
||||
{
|
||||
string[] commentLines = discimage.Comment.Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach(string line in commentLines) descriptorStream.WriteLine("// {0}", line);
|
||||
}
|
||||
|
||||
descriptorStream.WriteLine();
|
||||
|
||||
if(!string.IsNullOrEmpty(discimage.Mcn)) descriptorStream.WriteLine("CATALOG {0}", discimage.Mcn);
|
||||
|
||||
foreach(Track track in writingTracks)
|
||||
{
|
||||
descriptorStream.WriteLine();
|
||||
descriptorStream.WriteLine("// Track {0}", track.TrackSequence);
|
||||
|
||||
string subchannelType;
|
||||
|
||||
switch(track.TrackSubchannelType)
|
||||
{
|
||||
case TrackSubchannelType.Packed:
|
||||
case TrackSubchannelType.PackedInterleaved:
|
||||
subchannelType = " RW";
|
||||
break;
|
||||
case TrackSubchannelType.Raw:
|
||||
case TrackSubchannelType.RawInterleaved:
|
||||
subchannelType = " RW_RAW";
|
||||
break;
|
||||
default:
|
||||
subchannelType = "";
|
||||
break;
|
||||
}
|
||||
|
||||
descriptorStream.WriteLine("TRACK {0}{1}", GetTrackMode(track), subchannelType);
|
||||
|
||||
trackFlags.TryGetValue((byte)track.TrackSequence, out byte flagsByte);
|
||||
|
||||
CdFlags flags = (CdFlags)flagsByte;
|
||||
|
||||
descriptorStream.WriteLine("{0}COPY", flags.HasFlag(CdFlags.CopyPermitted) ? "" : "NO ");
|
||||
|
||||
if(track.TrackType == TrackType.Audio)
|
||||
{
|
||||
descriptorStream.WriteLine("{0}PRE_EMPHASIS", flags.HasFlag(CdFlags.PreEmphasis) ? "" : "NO ");
|
||||
descriptorStream.WriteLine("{0}_CHANNEL_AUDIO",
|
||||
flags.HasFlag(CdFlags.FourChannel) ? "FOUR" : "TWO");
|
||||
}
|
||||
|
||||
if(trackIsrcs.TryGetValue((byte)track.TrackSequence, out string isrc))
|
||||
descriptorStream.WriteLine("ISRC {0}", isrc);
|
||||
|
||||
(byte minute, byte second, byte frame)
|
||||
msf = LbaToMsf(track.TrackEndSector - track.TrackStartSector + 1);
|
||||
|
||||
descriptorStream.WriteLine("DATAFILE \"{0}\" #{1} {2:D2}:{3:D2}:{4:D2} // length in bytes: {5}",
|
||||
Path.GetFileName(track.TrackFile), track.TrackFileOffset, msf.minute,
|
||||
msf.second, msf.frame,
|
||||
(track.TrackEndSector - track.TrackStartSector + 1) *
|
||||
(ulong)(track.TrackRawBytesPerSector +
|
||||
(track.TrackSubchannelType != TrackSubchannelType.None ? 96 : 0)));
|
||||
|
||||
descriptorStream.WriteLine();
|
||||
}
|
||||
|
||||
descriptorStream.Flush();
|
||||
descriptorStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
discimage.Barcode = metadata.MediaBarcode;
|
||||
discimage.Comment = metadata.Comments;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
{
|
||||
if(data.Length != 1)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for track flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackFlags.Add((byte)track.TrackSequence, data[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
case SectorTagType.CdTrackIsrc:
|
||||
{
|
||||
if(data != null) trackIsrcs.Add((byte)track.TrackSequence, Encoding.UTF8.GetString(data));
|
||||
return true;
|
||||
}
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != 96)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStream
|
||||
.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)) + track.TrackRawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
case SectorTagType.CdTrackIsrc: return WriteSectorTag(data, sectorAddress, tag);
|
||||
case SectorTagType.CdSectorSubchannel:
|
||||
{
|
||||
if(track.TrackSubchannelType == 0)
|
||||
{
|
||||
ErrorMessage =
|
||||
$"Trying to write subchannel to track {track.TrackSequence}, that does not have subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % 96 != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for subchannel";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
{
|
||||
trackStream
|
||||
.Seek((long)(track.TrackFileOffset + (i + sectorAddress - track.TrackStartSector) * (ulong)(track.TrackRawBytesPerSector + 96)) + track.TrackRawBytesPerSector,
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, (int)(i * 96), 96);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
83
DiscImageChef.DiscImages/CDRWin/CDRWin.cs
Normal file
83
DiscImageChef.DiscImages/CDRWin/CDRWin.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CDRWin.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Implement track flags
|
||||
public partial class CdrWin : IWritableImage
|
||||
{
|
||||
IFilter cdrwinFilter;
|
||||
StreamReader cueStream;
|
||||
StreamWriter descriptorStream;
|
||||
CdrWinDisc discimage;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
/// <summary>Dictionary, index is track #, value is TrackFile</summary>
|
||||
Dictionary<uint, ulong> offsetmap;
|
||||
bool separateTracksWriting;
|
||||
Dictionary<byte, byte> trackFlags;
|
||||
Dictionary<byte, string> trackIsrcs;
|
||||
string writingBaseName;
|
||||
Dictionary<uint, FileStream> writingStreams;
|
||||
List<Track> writingTracks;
|
||||
|
||||
public CdrWin()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = true,
|
||||
HasSessions = true,
|
||||
Version = null,
|
||||
ApplicationVersion = null,
|
||||
MediaTitle = null,
|
||||
Creator = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
161
DiscImageChef.DiscImages/CDRWin/Constants.cs
Normal file
161
DiscImageChef.DiscImages/CDRWin/Constants.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
// Type for FILE entity
|
||||
/// <summary>Data as-is in little-endian</summary>
|
||||
const string CDRWIN_DISK_TYPE_LITTLE_ENDIAN = "BINARY";
|
||||
/// <summary>Data as-is in big-endian</summary>
|
||||
const string CDRWIN_DISK_TYPE_BIG_ENDIAN = "MOTOROLA";
|
||||
/// <summary>Audio in Apple AIF file</summary>
|
||||
const string CDRWIN_DISK_TYPE_AIFF = "AIFF";
|
||||
/// <summary>Audio in Microsoft WAV file</summary>
|
||||
const string CDRWIN_DISK_TYPE_RIFF = "WAVE";
|
||||
/// <summary>Audio in MP3 file</summary>
|
||||
const string CDRWIN_DISK_TYPE_MP3 = "MP3";
|
||||
|
||||
// Type for TRACK entity
|
||||
/// <summary>Audio track, 2352 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_AUDIO = "AUDIO";
|
||||
/// <summary>CD+G track, 2448 bytes/sector (audio+subchannel)</summary>
|
||||
const string CDRWIN_TRACK_TYPE_CDG = "CDG";
|
||||
/// <summary>Mode 1 track, cooked, 2048 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE1 = "MODE1/2048";
|
||||
/// <summary>Mode 1 track, raw, 2352 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE1_RAW = "MODE1/2352";
|
||||
/// <summary>Mode 2 form 1 track, cooked, 2048 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE2_FORM1 = "MODE2/2048";
|
||||
/// <summary>Mode 2 form 2 track, cooked, 2324 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE2_FORM2 = "MODE2/2324";
|
||||
/// <summary>Mode 2 formless track, cooked, 2336 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE2_FORMLESS = "MODE2/2336";
|
||||
/// <summary>Mode 2 track, raw, 2352 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_MODE2_RAW = "MODE2/2352";
|
||||
/// <summary>CD-i track, cooked, 2336 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_CDI = "CDI/2336";
|
||||
/// <summary>CD-i track, raw, 2352 bytes/sector</summary>
|
||||
const string CDRWIN_TRACK_TYPE_CDI_RAW = "CDI/2352";
|
||||
|
||||
// Type for REM ORIGINAL MEDIA-TYPE entity
|
||||
/// <summary>DiskType.CD</summary>
|
||||
const string CDRWIN_DISK_TYPE_CD = "CD";
|
||||
/// <summary>DiskType.CDRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_CDRW = "CD-RW";
|
||||
/// <summary>DiskType.CDMRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_CDMRW = "CD-MRW";
|
||||
/// <summary>DiskType.CDMRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_CDMRW2 = "CD-(MRW)";
|
||||
/// <summary>DiskType.DVDROM</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVD = "DVD";
|
||||
/// <summary>DiskType.DVDPRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPMRW = "DVD+MRW";
|
||||
/// <summary>DiskType.DVDPRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPMRW2 = "DVD+(MRW)";
|
||||
/// <summary>DiskType.DVDPRWDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPMRWDL = "DVD+MRW DL";
|
||||
/// <summary>DiskType.DVDPRWDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPMRWDL2 = "DVD+(MRW) DL";
|
||||
/// <summary>DiskType.DVDPR</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPR = "DVD+R";
|
||||
/// <summary>DiskType.DVDPRDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPRDL = "DVD+R DL";
|
||||
/// <summary>DiskType.DVDPRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPRW = "DVD+RW";
|
||||
/// <summary>DiskType.DVDPRWDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPRWDL = "DVD+RW DL";
|
||||
/// <summary>DiskType.DVDPR</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDPVR = "DVD+VR";
|
||||
/// <summary>DiskType.DVDRAM</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDRAM = "DVD-RAM";
|
||||
/// <summary>DiskType.DVDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDR = "DVD-R";
|
||||
/// <summary>DiskType.DVDRDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDRDL = "DVD-R DL";
|
||||
/// <summary>DiskType.DVDRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDRW = "DVD-RW";
|
||||
/// <summary>DiskType.DVDRWDL</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDRWDL = "DVD-RW DL";
|
||||
/// <summary>DiskType.DVDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDVR = "DVD-VR";
|
||||
/// <summary>DiskType.DVDRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_DVDRW2 = "DVDRW";
|
||||
/// <summary>DiskType.HDDVDROM</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVD = "HD DVD";
|
||||
/// <summary>DiskType.HDDVDRAM</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVDRAM = "HD DVD-RAM";
|
||||
/// <summary>DiskType.HDDVDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVDR = "HD DVD-R";
|
||||
/// <summary>DiskType.HDDVDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVDRDL = "HD DVD-R DL";
|
||||
/// <summary>DiskType.HDDVDRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVDRW = "HD DVD-RW";
|
||||
/// <summary>DiskType.HDDVDRW</summary>
|
||||
const string CDRWIN_DISK_TYPE_HDDVDRWDL = "HD DVD-RW DL";
|
||||
/// <summary>DiskType.BDROM</summary>
|
||||
const string CDRWIN_DISK_TYPE_BD = "BD";
|
||||
/// <summary>DiskType.BDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_BDR = "BD-R";
|
||||
/// <summary>DiskType.BDRE</summary>
|
||||
const string CDRWIN_DISK_TYPE_BDRE = "BD-RE";
|
||||
/// <summary>DiskType.BDR</summary>
|
||||
const string CDRWIN_DISK_TYPE_BDRDL = "BD-R DL";
|
||||
/// <summary>DiskType.BDRE</summary>
|
||||
const string CDRWIN_DISK_TYPE_BDREDL = "BD-RE DL";
|
||||
|
||||
const string REGEX_SESSION = @"\bREM\s+SESSION\s+(?<number>\d+).*$";
|
||||
const string REGEX_MEDIA_TYPE = @"\bREM\s+ORIGINAL MEDIA-TYPE:\s+(?<mediatype>.+)$";
|
||||
const string REGEX_LEAD_OUT = @"\bREM\s+LEAD-OUT\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
|
||||
// Not checked
|
||||
const string REGEX_LBA = @"\bREM MSF:\s+(?<msf>[\d]+:[\d]+:[\d]+)\s+=\s+LBA:\s+(?<lba>[\d]+)$";
|
||||
const string REGEX_DISC_ID = @"\bDISC_ID\s+(?<diskid>[\da-f]{8})$";
|
||||
const string REGEX_BARCODE = @"\bUPC_EAN\s+(?<barcode>[\d]{12,13})$";
|
||||
const string REGEX_COMMENT = @"\bREM\s+(?<comment>.+)$";
|
||||
const string REGEX_CDTEXT = @"\bCDTEXTFILE\s+(?<filename>.+)$";
|
||||
const string REGEX_MCN = @"^\s*CATALOG\s*(?<catalog>[\x21-\x7F]{13})$";
|
||||
const string REGEX_TITLE = @"\bTITLE\s+(?<title>.+)$";
|
||||
const string REGEX_GENRE = @"\bGENRE\s+(?<genre>.+)$";
|
||||
const string REGEX_ARRANGER = @"\bARRANGER\s+(?<arranger>.+)$";
|
||||
const string REGEX_COMPOSER = @"\bCOMPOSER\s+(?<composer>.+)$";
|
||||
const string REGEX_PERFORMER = @"\bPERFORMER\s+(?<performer>.+)$";
|
||||
const string REGEX_SONGWRITER = @"\bSONGWRITER\s+(?<songwriter>.+)$";
|
||||
const string REGEX_FILE = @"\bFILE\s+(?<filename>.+)\s+(?<type>\S+)$";
|
||||
const string REGEX_TRACK = @"\bTRACK\s+(?<number>\d+)\s+(?<type>\S+)$";
|
||||
const string REGEX_ISRC = @"\bISRC\s+(?<isrc>\w{12})$";
|
||||
const string REGEX_INDEX = @"\bINDEX\s+(?<index>\d+)\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
|
||||
const string REGEX_PREGAP = @"\bPREGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
|
||||
const string REGEX_POSTGAP = @"\bPOSTGAP\s+(?<msf>[\d]+:[\d]+:[\d]+)$";
|
||||
const string REGEX_FLAGS = @"\bFLAGS\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\s*)+$";
|
||||
}
|
||||
}
|
||||
242
DiscImageChef.DiscImages/CDRWin/Helpers.cs
Normal file
242
DiscImageChef.DiscImages/CDRWin/Helpers.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Helpers.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains helpers for CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
static ulong CdrWinMsftoLba(string msf)
|
||||
{
|
||||
string[] msfElements = msf.Split(':');
|
||||
ulong minute = ulong.Parse(msfElements[0]);
|
||||
ulong second = ulong.Parse(msfElements[1]);
|
||||
ulong frame = ulong.Parse(msfElements[2]);
|
||||
|
||||
ulong sectors = minute * 60 * 75 + second * 75 + frame;
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
static ushort CdrWinTrackTypeToBytesPerSector(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRWIN_TRACK_TYPE_MODE1:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM1: return 2048;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM2: return 2324;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORMLESS:
|
||||
case CDRWIN_TRACK_TYPE_CDI: return 2336;
|
||||
case CDRWIN_TRACK_TYPE_AUDIO:
|
||||
case CDRWIN_TRACK_TYPE_MODE1_RAW:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_RAW:
|
||||
case CDRWIN_TRACK_TYPE_CDG:
|
||||
case CDRWIN_TRACK_TYPE_CDI_RAW: return 2352;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static ushort CdrWinTrackTypeToCookedBytesPerSector(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRWIN_TRACK_TYPE_MODE1:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM1:
|
||||
case CDRWIN_TRACK_TYPE_MODE1_RAW: return 2048;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM2: return 2324;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORMLESS:
|
||||
case CDRWIN_TRACK_TYPE_CDI:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_RAW:
|
||||
case CDRWIN_TRACK_TYPE_CDI_RAW: return 2336;
|
||||
case CDRWIN_TRACK_TYPE_CDG:
|
||||
case CDRWIN_TRACK_TYPE_AUDIO: return 2352;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static TrackType CdrWinTrackTypeToTrackType(string trackType)
|
||||
{
|
||||
switch(trackType)
|
||||
{
|
||||
case CDRWIN_TRACK_TYPE_MODE1:
|
||||
case CDRWIN_TRACK_TYPE_MODE1_RAW: return TrackType.CdMode1;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM1: return TrackType.CdMode2Form1;
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORM2: return TrackType.CdMode2Form2;
|
||||
case CDRWIN_TRACK_TYPE_CDI_RAW:
|
||||
case CDRWIN_TRACK_TYPE_CDI:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_RAW:
|
||||
case CDRWIN_TRACK_TYPE_MODE2_FORMLESS: return TrackType.CdMode2Formless;
|
||||
case CDRWIN_TRACK_TYPE_AUDIO:
|
||||
case CDRWIN_TRACK_TYPE_CDG: return TrackType.Audio;
|
||||
default: return TrackType.Data;
|
||||
}
|
||||
}
|
||||
|
||||
static MediaType CdrWinIsoBusterDiscTypeToMediaType(string discType)
|
||||
{
|
||||
switch(discType)
|
||||
{
|
||||
case CDRWIN_DISK_TYPE_CD: return MediaType.CD;
|
||||
case CDRWIN_DISK_TYPE_CDRW:
|
||||
case CDRWIN_DISK_TYPE_CDMRW:
|
||||
case CDRWIN_DISK_TYPE_CDMRW2: return MediaType.CDRW;
|
||||
case CDRWIN_DISK_TYPE_DVD: return MediaType.DVDROM;
|
||||
case CDRWIN_DISK_TYPE_DVDPRW:
|
||||
case CDRWIN_DISK_TYPE_DVDPMRW:
|
||||
case CDRWIN_DISK_TYPE_DVDPMRW2: return MediaType.DVDPRW;
|
||||
case CDRWIN_DISK_TYPE_DVDPRWDL:
|
||||
case CDRWIN_DISK_TYPE_DVDPMRWDL:
|
||||
case CDRWIN_DISK_TYPE_DVDPMRWDL2: return MediaType.DVDPRWDL;
|
||||
case CDRWIN_DISK_TYPE_DVDPR:
|
||||
case CDRWIN_DISK_TYPE_DVDPVR: return MediaType.DVDPR;
|
||||
case CDRWIN_DISK_TYPE_DVDPRDL: return MediaType.DVDPRDL;
|
||||
case CDRWIN_DISK_TYPE_DVDRAM: return MediaType.DVDRAM;
|
||||
case CDRWIN_DISK_TYPE_DVDVR:
|
||||
case CDRWIN_DISK_TYPE_DVDR: return MediaType.DVDR;
|
||||
case CDRWIN_DISK_TYPE_DVDRDL: return MediaType.DVDRDL;
|
||||
case CDRWIN_DISK_TYPE_DVDRW:
|
||||
case CDRWIN_DISK_TYPE_DVDRWDL:
|
||||
case CDRWIN_DISK_TYPE_DVDRW2: return MediaType.DVDRW;
|
||||
case CDRWIN_DISK_TYPE_HDDVD: return MediaType.HDDVDROM;
|
||||
case CDRWIN_DISK_TYPE_HDDVDRAM: return MediaType.HDDVDRAM;
|
||||
case CDRWIN_DISK_TYPE_HDDVDR:
|
||||
case CDRWIN_DISK_TYPE_HDDVDRDL: return MediaType.HDDVDR;
|
||||
case CDRWIN_DISK_TYPE_HDDVDRW:
|
||||
case CDRWIN_DISK_TYPE_HDDVDRWDL: return MediaType.HDDVDRW;
|
||||
case CDRWIN_DISK_TYPE_BD: return MediaType.BDROM;
|
||||
case CDRWIN_DISK_TYPE_BDR:
|
||||
case CDRWIN_DISK_TYPE_BDRDL: return MediaType.BDR;
|
||||
case CDRWIN_DISK_TYPE_BDRE:
|
||||
case CDRWIN_DISK_TYPE_BDREDL: return MediaType.BDRE;
|
||||
default: return MediaType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static (byte minute, byte second, byte frame) LbaToMsf(ulong sector)
|
||||
{
|
||||
return ((byte)(sector / 75 / 60), (byte)(sector / 75 % 60), (byte)(sector % 75));
|
||||
}
|
||||
|
||||
static string GetTrackMode(Track track)
|
||||
{
|
||||
switch(track.TrackType)
|
||||
{
|
||||
case TrackType.Audio when track.TrackRawBytesPerSector == 2352: return CDRWIN_TRACK_TYPE_AUDIO;
|
||||
case TrackType.Data: return CDRWIN_TRACK_TYPE_MODE1;
|
||||
case TrackType.CdMode1 when track.TrackRawBytesPerSector == 2352: return CDRWIN_TRACK_TYPE_MODE1_RAW;
|
||||
case TrackType.CdMode2Formless
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRWIN_TRACK_TYPE_MODE2_FORMLESS;
|
||||
case TrackType.CdMode2Form1
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRWIN_TRACK_TYPE_MODE2_FORM1;
|
||||
case TrackType.CdMode2Form2
|
||||
when track.TrackRawBytesPerSector != 2352: return CDRWIN_TRACK_TYPE_MODE2_FORM2;
|
||||
case TrackType.CdMode2Formless when track.TrackRawBytesPerSector == 2352:
|
||||
case TrackType.CdMode2Form1 when track.TrackRawBytesPerSector == 2352:
|
||||
case TrackType.CdMode2Form2
|
||||
when track.TrackRawBytesPerSector == 2352: return CDRWIN_TRACK_TYPE_MODE2_RAW;
|
||||
default: return CDRWIN_TRACK_TYPE_MODE1;
|
||||
}
|
||||
}
|
||||
|
||||
static string MediaTypeToCdrwinType(MediaType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case MediaType.BDRXL:
|
||||
case MediaType.BDR: return CDRWIN_DISK_TYPE_BDR;
|
||||
case MediaType.BDREXL:
|
||||
case MediaType.BDRE: return CDRWIN_DISK_TYPE_BDRE;
|
||||
case MediaType.BDROM:
|
||||
case MediaType.CBHD:
|
||||
case MediaType.PS3BD:
|
||||
case MediaType.PS4BD:
|
||||
case MediaType.UDO:
|
||||
case MediaType.UDO2:
|
||||
case MediaType.UDO2_WORM: return CDRWIN_DISK_TYPE_BD;
|
||||
case MediaType.CDV:
|
||||
case MediaType.DDCD:
|
||||
case MediaType.DDCDR:
|
||||
case MediaType.DDCDRW:
|
||||
case MediaType.CDPLUS:
|
||||
case MediaType.CDR:
|
||||
case MediaType.CDROM:
|
||||
case MediaType.CDROMXA:
|
||||
case MediaType.CD:
|
||||
case MediaType.CDDA:
|
||||
case MediaType.CDEG:
|
||||
case MediaType.CDG:
|
||||
case MediaType.CDI:
|
||||
case MediaType.CDMIDI:
|
||||
case MediaType.DTSCD:
|
||||
case MediaType.JaguarCD:
|
||||
case MediaType.MEGACD:
|
||||
case MediaType.PD650:
|
||||
case MediaType.PD650_WORM:
|
||||
case MediaType.PS1CD:
|
||||
case MediaType.PS2CD:
|
||||
case MediaType.SuperCDROM2:
|
||||
case MediaType.SVCD:
|
||||
case MediaType.SVOD:
|
||||
case MediaType.SATURNCD:
|
||||
case MediaType.ThreeDO:
|
||||
case MediaType.VCD:
|
||||
case MediaType.VCDHD: return CDRWIN_DISK_TYPE_CD;
|
||||
case MediaType.CDMRW: return CDRWIN_DISK_TYPE_CDMRW;
|
||||
case MediaType.CDRW: return CDRWIN_DISK_TYPE_CDRW;
|
||||
case MediaType.DVDPR: return CDRWIN_DISK_TYPE_DVDPR;
|
||||
case MediaType.DVDPRDL: return CDRWIN_DISK_TYPE_DVDPRDL;
|
||||
case MediaType.DVDPRW: return CDRWIN_DISK_TYPE_DVDPRW;
|
||||
case MediaType.DVDPRWDL: return CDRWIN_DISK_TYPE_DVDPRWDL;
|
||||
case MediaType.DVDR: return CDRWIN_DISK_TYPE_DVDR;
|
||||
case MediaType.DVDRAM: return CDRWIN_DISK_TYPE_DVDRAM;
|
||||
case MediaType.DVDRDL: return CDRWIN_DISK_TYPE_DVDRDL;
|
||||
case MediaType.DVDDownload:
|
||||
case MediaType.DVDROM:
|
||||
case MediaType.UMD:
|
||||
case MediaType.PS2DVD:
|
||||
case MediaType.PS3DVD: return CDRWIN_DISK_TYPE_DVD;
|
||||
case MediaType.DVDRW: return CDRWIN_DISK_TYPE_DVDRW;
|
||||
case MediaType.DVDRWDL: return CDRWIN_DISK_TYPE_DVDRWDL;
|
||||
case MediaType.HDDVDR: return CDRWIN_DISK_TYPE_HDDVDR;
|
||||
case MediaType.HDDVDRAM: return CDRWIN_DISK_TYPE_HDDVDRAM;
|
||||
case MediaType.HDDVDRDL: return CDRWIN_DISK_TYPE_HDDVDRDL;
|
||||
case MediaType.HDDVDROM: return CDRWIN_DISK_TYPE_HDDVD;
|
||||
case MediaType.HDDVDRW: return CDRWIN_DISK_TYPE_HDDVDRW;
|
||||
case MediaType.HDDVDRWDL: return CDRWIN_DISK_TYPE_HDDVDRWDL;
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
105
DiscImageChef.DiscImages/CDRWin/Identify.cs
Normal file
105
DiscImageChef.DiscImages/CDRWin/Identify.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Identify.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Identifies CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
// Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()).
|
||||
public bool Identify(IFilter imageFilter)
|
||||
{
|
||||
cdrwinFilter = imageFilter;
|
||||
|
||||
try
|
||||
{
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
byte[] testArray = new byte[512];
|
||||
imageFilter.GetDataForkStream().Read(testArray, 0, 512);
|
||||
imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin);
|
||||
// Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin
|
||||
bool twoConsecutiveNulls = false;
|
||||
for(int i = 0; i < 512; i++)
|
||||
{
|
||||
if(i >= imageFilter.GetDataForkStream().Length) break;
|
||||
|
||||
if(testArray[i] == 0)
|
||||
{
|
||||
if(twoConsecutiveNulls) return false;
|
||||
|
||||
twoConsecutiveNulls = true;
|
||||
}
|
||||
else twoConsecutiveNulls = false;
|
||||
|
||||
if(testArray[i] < 0x20 && testArray[i] != 0x0A && testArray[i] != 0x0D && testArray[i] != 0x00)
|
||||
return false;
|
||||
}
|
||||
|
||||
cueStream = new StreamReader(cdrwinFilter.GetDataForkStream());
|
||||
|
||||
while(cueStream.Peek() >= 0)
|
||||
{
|
||||
string line = cueStream.ReadLine();
|
||||
|
||||
Regex sr = new Regex(REGEX_SESSION);
|
||||
Regex rr = new Regex(REGEX_COMMENT);
|
||||
Regex cr = new Regex(REGEX_MCN);
|
||||
Regex fr = new Regex(REGEX_FILE);
|
||||
Regex tr = new Regex(REGEX_CDTEXT);
|
||||
|
||||
// First line must be SESSION, REM, CATALOG, FILE or CDTEXTFILE.
|
||||
Match sm = sr.Match(line ?? throw new InvalidOperationException());
|
||||
Match rm = rr.Match(line);
|
||||
Match cm = cr.Match(line);
|
||||
Match fm = fr.Match(line);
|
||||
Match tm = tr.Match(line);
|
||||
|
||||
return sm.Success || rm.Success || cm.Success || fm.Success || tm.Success;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", cdrwinFilter);
|
||||
DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
|
||||
DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
129
DiscImageChef.DiscImages/CDRWin/Properties.cs
Normal file
129
DiscImageChef.DiscImages/CDRWin/Properties.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Properties.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains properties for CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
public ImageInfo Info => imageInfo;
|
||||
public string Name => "CDRWin cuesheet";
|
||||
public Guid Id => new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F");
|
||||
public string Format => "CDRWin CUESheet";
|
||||
public List<Partition> Partitions { get; private set; }
|
||||
public List<Track> Tracks
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Track> tracks = new List<Track>();
|
||||
|
||||
ulong previousStartSector = 0;
|
||||
|
||||
foreach(CdrWinTrack cdrTrack in discimage.Tracks)
|
||||
{
|
||||
Track dicTrack = new Track
|
||||
{
|
||||
Indexes = cdrTrack.Indexes,
|
||||
TrackDescription = cdrTrack.Title,
|
||||
TrackStartSector = previousStartSector,
|
||||
TrackPregap = cdrTrack.Pregap,
|
||||
TrackSession = cdrTrack.Session,
|
||||
TrackSequence = cdrTrack.Sequence,
|
||||
TrackType = CdrWinTrackTypeToTrackType(cdrTrack.Tracktype),
|
||||
TrackFile = cdrTrack.Trackfile.Datafilter.GetFilename(),
|
||||
TrackFilter = cdrTrack.Trackfile.Datafilter,
|
||||
TrackFileOffset = cdrTrack.Trackfile.Offset,
|
||||
TrackFileType = cdrTrack.Trackfile.Filetype,
|
||||
TrackRawBytesPerSector = cdrTrack.Bps,
|
||||
TrackBytesPerSector = CdrWinTrackTypeToCookedBytesPerSector(cdrTrack.Tracktype)
|
||||
};
|
||||
dicTrack.TrackEndSector = dicTrack.TrackStartSector + cdrTrack.Sectors - 1;
|
||||
|
||||
/*if(!cdrTrack.Indexes.TryGetValue(0, out dicTrack.TrackStartSector))
|
||||
cdrTrack.Indexes.TryGetValue(1, out dicTrack.TrackStartSector);*/
|
||||
if(cdrTrack.Tracktype == CDRWIN_TRACK_TYPE_CDG)
|
||||
{
|
||||
dicTrack.TrackSubchannelFilter = cdrTrack.Trackfile.Datafilter;
|
||||
dicTrack.TrackSubchannelFile = cdrTrack.Trackfile.Datafilter.GetFilename();
|
||||
dicTrack.TrackSubchannelOffset = cdrTrack.Trackfile.Offset;
|
||||
dicTrack.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
|
||||
}
|
||||
else dicTrack.TrackSubchannelType = TrackSubchannelType.None;
|
||||
|
||||
tracks.Add(dicTrack);
|
||||
previousStartSector = dicTrack.TrackEndSector + 1;
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
}
|
||||
public List<Session> Sessions => discimage.Sessions;
|
||||
public List<DumpHardwareType> DumpHardware => null;
|
||||
public CICMMetadataType CicmMetadata => null;
|
||||
public IEnumerable<MediaTagType> SupportedMediaTags => new[] {MediaTagType.CD_MCN, MediaTagType.CD_TEXT};
|
||||
public IEnumerable<SectorTagType> SupportedSectorTags =>
|
||||
new[]
|
||||
{
|
||||
SectorTagType.CdSectorEcc, SectorTagType.CdSectorEccP, SectorTagType.CdSectorEccQ,
|
||||
SectorTagType.CdSectorEdc, SectorTagType.CdSectorHeader, SectorTagType.CdSectorSubHeader,
|
||||
SectorTagType.CdSectorSync, SectorTagType.CdTrackFlags, SectorTagType.CdTrackIsrc
|
||||
};
|
||||
public IEnumerable<MediaType> SupportedMediaTypes =>
|
||||
new[]
|
||||
{
|
||||
MediaType.BDR, MediaType.BDRE, MediaType.BDREXL, MediaType.BDROM, MediaType.BDRXL, MediaType.CBHD,
|
||||
MediaType.CD, MediaType.CDDA, MediaType.CDEG, MediaType.CDG, MediaType.CDI, MediaType.CDMIDI,
|
||||
MediaType.CDMRW, MediaType.CDPLUS, MediaType.CDR, MediaType.CDROM, MediaType.CDROMXA, MediaType.CDRW,
|
||||
MediaType.CDV, MediaType.DDCD, MediaType.DDCDR, MediaType.DDCDRW, MediaType.DVDDownload,
|
||||
MediaType.DVDPR, MediaType.DVDPRDL, MediaType.DVDPRW, MediaType.DVDPRWDL, MediaType.DVDR,
|
||||
MediaType.DVDRAM, MediaType.DVDRDL, MediaType.DVDROM, MediaType.DVDRW, MediaType.DVDRWDL, MediaType.EVD,
|
||||
MediaType.FDDVD, MediaType.DTSCD, MediaType.FVD, MediaType.HDDVDR, MediaType.HDDVDRAM,
|
||||
MediaType.HDDVDRDL, MediaType.HDDVDROM, MediaType.HDDVDRW, MediaType.HDDVDRWDL, MediaType.HDVMD,
|
||||
MediaType.HVD, MediaType.JaguarCD, MediaType.MEGACD, MediaType.PD650, MediaType.PD650_WORM,
|
||||
MediaType.PS1CD, MediaType.PS2CD, MediaType.PS2DVD, MediaType.PS3BD, MediaType.PS3DVD, MediaType.PS4BD,
|
||||
MediaType.SuperCDROM2, MediaType.SVCD, MediaType.SVOD, MediaType.SATURNCD, MediaType.ThreeDO,
|
||||
MediaType.UDO, MediaType.UDO2, MediaType.UDO2_WORM, MediaType.UMD, MediaType.VCD, MediaType.VCDHD,
|
||||
MediaType.NeoGeoCD, MediaType.PCFX
|
||||
};
|
||||
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
|
||||
new[] {("separate", typeof(bool), "Write each track to a separate file.")};
|
||||
public IEnumerable<string> KnownExtensions => new[] {".cue"};
|
||||
public bool IsWriting { get; private set; }
|
||||
public string ErrorMessage { get; private set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
132
DiscImageChef.DiscImages/CDRWin/Structs.cs
Normal file
132
DiscImageChef.DiscImages/CDRWin/Structs.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Structs.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains structures for CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
struct CdrWinTrackFile
|
||||
{
|
||||
/// <summary>Track #</summary>
|
||||
public uint Sequence;
|
||||
/// <summary>Filter of file containing track</summary>
|
||||
public IFilter Datafilter;
|
||||
/// <summary>Offset of track start in file</summary>
|
||||
public ulong Offset;
|
||||
/// <summary>Type of file</summary>
|
||||
public string Filetype;
|
||||
}
|
||||
|
||||
struct CdrWinTrack
|
||||
{
|
||||
/// <summary>Track #</summary>
|
||||
public uint Sequence;
|
||||
/// <summary>Track title (from CD-Text)</summary>
|
||||
public string Title;
|
||||
/// <summary>Track genre (from CD-Text)</summary>
|
||||
public string Genre;
|
||||
/// <summary>Track arranger (from CD-Text)</summary>
|
||||
public string Arranger;
|
||||
/// <summary>Track composer (from CD-Text)</summary>
|
||||
public string Composer;
|
||||
/// <summary>Track performer (from CD-Text)</summary>
|
||||
public string Performer;
|
||||
/// <summary>Track song writer (from CD-Text)</summary>
|
||||
public string Songwriter;
|
||||
/// <summary>Track ISRC</summary>
|
||||
public string Isrc;
|
||||
/// <summary>File struct for this track</summary>
|
||||
public CdrWinTrackFile Trackfile;
|
||||
/// <summary>Indexes on this track</summary>
|
||||
public Dictionary<int, ulong> Indexes;
|
||||
/// <summary>Track pre-gap in sectors</summary>
|
||||
public ulong Pregap;
|
||||
/// <summary>Track post-gap in sectors</summary>
|
||||
public ulong Postgap;
|
||||
/// <summary>Digical Copy Permitted</summary>
|
||||
public bool FlagDcp;
|
||||
/// <summary>Track is quadraphonic</summary>
|
||||
public bool Flag4ch;
|
||||
/// <summary>Track has preemphasis</summary>
|
||||
public bool FlagPre;
|
||||
/// <summary>Track has SCMS</summary>
|
||||
public bool FlagScms;
|
||||
/// <summary>Bytes per sector</summary>
|
||||
public ushort Bps;
|
||||
/// <summary>Sectors in track</summary>
|
||||
public ulong Sectors;
|
||||
/// <summary>Track type</summary>
|
||||
public string Tracktype;
|
||||
/// <summary>Track session</summary>
|
||||
public ushort Session;
|
||||
}
|
||||
|
||||
struct CdrWinDisc
|
||||
{
|
||||
/// <summary>Disk title (from CD-Text)</summary>
|
||||
public string Title;
|
||||
/// <summary>Disk genre (from CD-Text)</summary>
|
||||
public string Genre;
|
||||
/// <summary>Disk arranger (from CD-Text)</summary>
|
||||
public string Arranger;
|
||||
/// <summary>Disk composer (from CD-Text)</summary>
|
||||
public string Composer;
|
||||
/// <summary>Disk performer (from CD-Text)</summary>
|
||||
public string Performer;
|
||||
/// <summary>Disk song writer (from CD-Text)</summary>
|
||||
public string Songwriter;
|
||||
/// <summary>Media catalog number</summary>
|
||||
public string Mcn;
|
||||
/// <summary>Disk type</summary>
|
||||
public MediaType Disktype;
|
||||
/// <summary>Disk type string</summary>
|
||||
public string Disktypestr;
|
||||
/// <summary>Disk CDDB ID</summary>
|
||||
public string DiskId;
|
||||
/// <summary>Disk UPC/EAN</summary>
|
||||
public string Barcode;
|
||||
/// <summary>Sessions</summary>
|
||||
public List<Session> Sessions;
|
||||
/// <summary>Tracks</summary>
|
||||
public List<CdrWinTrack> Tracks;
|
||||
/// <summary>Disk comment</summary>
|
||||
public string Comment;
|
||||
/// <summary>File containing CD-Text</summary>
|
||||
public string Cdtextfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
DiscImageChef.DiscImages/CDRWin/Unsupported.cs
Normal file
42
DiscImageChef.DiscImages/CDRWin/Unsupported.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Unsupported.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains features unsupported by CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
public bool? VerifyMediaImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
508
DiscImageChef.DiscImages/CDRWin/Write.cs
Normal file
508
DiscImageChef.DiscImages/CDRWin/Write.cs
Normal file
@@ -0,0 +1,508 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Write.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Writes CDRWin cuesheets (cue/bin).
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
using Schemas;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class CdrWin
|
||||
{
|
||||
public bool Create(string path, MediaType mediaType, Dictionary<string, string> options, ulong sectors,
|
||||
uint sectorSize)
|
||||
{
|
||||
if(options != null)
|
||||
{
|
||||
if(options.TryGetValue("separate", out string tmpValue))
|
||||
{
|
||||
if(!bool.TryParse(tmpValue, out separateTracksWriting))
|
||||
{
|
||||
ErrorMessage = "Invalid value for split option";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(separateTracksWriting)
|
||||
{
|
||||
ErrorMessage = "Separate tracksnot yet implemented";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else separateTracksWriting = false;
|
||||
|
||||
if(!SupportedMediaTypes.Contains(mediaType))
|
||||
{
|
||||
ErrorMessage = $"Unsupport media format {mediaType}";
|
||||
return false;
|
||||
}
|
||||
|
||||
imageInfo = new ImageInfo {MediaType = mediaType, SectorSize = sectorSize, Sectors = sectors};
|
||||
|
||||
// TODO: Separate tracks
|
||||
try
|
||||
{
|
||||
writingBaseName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
|
||||
descriptorStream = new StreamWriter(path, false, Encoding.ASCII);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
ErrorMessage = $"Could not create new image file, exception {e.Message}";
|
||||
return false;
|
||||
}
|
||||
|
||||
discimage = new CdrWinDisc
|
||||
{
|
||||
Disktype = mediaType,
|
||||
Sessions = new List<Session>(),
|
||||
Tracks = new List<CdrWinTrack>()
|
||||
};
|
||||
|
||||
trackFlags = new Dictionary<byte, byte>();
|
||||
trackIsrcs = new Dictionary<byte, string>();
|
||||
|
||||
IsWriting = true;
|
||||
ErrorMessage = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteMediaTag(byte[] data, MediaTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case MediaTagType.CD_MCN:
|
||||
discimage.Mcn = Encoding.ASCII.GetString(data);
|
||||
return true;
|
||||
case MediaTagType.CD_TEXT:
|
||||
FileStream cdTextStream = new FileStream(writingBaseName + "_cdtext.bin", FileMode.Create,
|
||||
FileAccess.ReadWrite, FileShare.None);
|
||||
cdTextStream.Write(data, 0, data.Length);
|
||||
discimage.Cdtextfile = Path.GetFileName(cdTextStream.Name);
|
||||
cdTextStream.Close();
|
||||
return true;
|
||||
default:
|
||||
ErrorMessage = $"Unsupported media tag {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSector(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectors(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(track.TrackBytesPerSector != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Invalid write mode for this sector";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorLong(byte[] data, ulong sectorAddress)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length != track.TrackRawBytesPerSector)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteSectorsLong(byte[] data, ulong sectorAddress, uint length)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
FileStream trackStream = writingStreams.FirstOrDefault(kvp => kvp.Key == track.TrackSequence).Value;
|
||||
|
||||
if(trackStream == null)
|
||||
{
|
||||
ErrorMessage = $"Can't found file containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sectorAddress + length > track.TrackEndSector + 1)
|
||||
{
|
||||
ErrorMessage = "Can't cross tracks";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data.Length % track.TrackRawBytesPerSector != 0)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStream.Seek((long)(track.TrackFileOffset + (sectorAddress - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector),
|
||||
SeekOrigin.Begin);
|
||||
trackStream.Write(data, 0, data.Length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetTracks(List<Track> tracks)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tracks == null || tracks.Count == 0)
|
||||
{
|
||||
ErrorMessage = "Invalid tracks sent";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(writingTracks != null && writingStreams != null)
|
||||
foreach(FileStream oldTrack in writingStreams.Select(t => t.Value).Distinct())
|
||||
oldTrack.Close();
|
||||
|
||||
ulong currentOffset = 0;
|
||||
writingTracks = new List<Track>();
|
||||
foreach(Track track in tracks.OrderBy(t => t.TrackSequence))
|
||||
{
|
||||
Track newTrack = track;
|
||||
newTrack.TrackFile = separateTracksWriting
|
||||
? writingBaseName + $"_track{track.TrackSequence:D2}.bin"
|
||||
: writingBaseName + ".bin";
|
||||
newTrack.TrackFileOffset = separateTracksWriting ? 0 : currentOffset;
|
||||
writingTracks.Add(newTrack);
|
||||
currentOffset += (ulong)newTrack.TrackRawBytesPerSector *
|
||||
(newTrack.TrackEndSector - newTrack.TrackStartSector + 1);
|
||||
}
|
||||
|
||||
writingStreams = new Dictionary<uint, FileStream>();
|
||||
if(separateTracksWriting)
|
||||
foreach(Track track in writingTracks)
|
||||
writingStreams.Add(track.TrackSequence,
|
||||
new FileStream(track.TrackFile, FileMode.OpenOrCreate, FileAccess.ReadWrite,
|
||||
FileShare.None));
|
||||
else
|
||||
{
|
||||
FileStream jointstream = new FileStream(writingBaseName + ".bin", FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite, FileShare.None);
|
||||
foreach(Track track in writingTracks) writingStreams.Add(track.TrackSequence, jointstream);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Image is not opened for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(separateTracksWriting)
|
||||
foreach(FileStream writingStream in writingStreams.Values)
|
||||
{
|
||||
writingStream.Flush();
|
||||
writingStream.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
writingStreams.First().Value.Flush();
|
||||
writingStreams.First().Value.Close();
|
||||
}
|
||||
|
||||
int currentSession = 0;
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(discimage.Comment))
|
||||
{
|
||||
string[] commentLines = discimage.Comment.Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach(string line in commentLines) descriptorStream.WriteLine("REM {0}", line);
|
||||
}
|
||||
|
||||
descriptorStream.WriteLine("REM ORIGINAL MEDIA-TYPE {0}", MediaTypeToCdrwinType(imageInfo.MediaType));
|
||||
|
||||
if(!string.IsNullOrEmpty(discimage.Cdtextfile))
|
||||
descriptorStream.WriteLine("CDTEXTFILE \"{0}\"", Path.GetFileName(discimage.Cdtextfile));
|
||||
|
||||
if(!string.IsNullOrEmpty(discimage.Title)) descriptorStream.WriteLine("TITLE {0}", discimage.Title);
|
||||
|
||||
if(!string.IsNullOrEmpty(discimage.Mcn)) descriptorStream.WriteLine("CATALOG {0}", discimage.Mcn);
|
||||
|
||||
if(!string.IsNullOrEmpty(discimage.Barcode)) descriptorStream.WriteLine("UPC_EAN {0}", discimage.Barcode);
|
||||
|
||||
if(!separateTracksWriting)
|
||||
descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(writingStreams.First().Value.Name));
|
||||
|
||||
foreach(Track track in writingTracks)
|
||||
{
|
||||
if(track.TrackSession > currentSession) descriptorStream.WriteLine("REM SESSION {0}", ++currentSession);
|
||||
|
||||
if(separateTracksWriting)
|
||||
descriptorStream.WriteLine("FILE \"{0}\" BINARY", Path.GetFileName(track.TrackFile));
|
||||
|
||||
(byte minute, byte second, byte frame) msf = LbaToMsf(track.TrackStartSector);
|
||||
descriptorStream.WriteLine(" TRACK {0:D2} {1}", track.TrackSequence, GetTrackMode(track));
|
||||
|
||||
if(trackFlags.TryGetValue((byte)track.TrackSequence, out byte flagsByte))
|
||||
if(flagsByte != 0 && flagsByte != (byte)CdFlags.DataTrack)
|
||||
{
|
||||
CdFlags flags = (CdFlags)flagsByte;
|
||||
descriptorStream.WriteLine(" FLAGS{0}{1}{2}",
|
||||
flags.HasFlag(CdFlags.CopyPermitted) ? " DCP" : "",
|
||||
flags.HasFlag(CdFlags.FourChannel) ? " 4CH" : "",
|
||||
flags.HasFlag(CdFlags.PreEmphasis) ? " PRE" : "");
|
||||
}
|
||||
|
||||
if(trackIsrcs.TryGetValue((byte)track.TrackSequence, out string isrc))
|
||||
descriptorStream.WriteLine(" ISRC {0}", isrc);
|
||||
|
||||
descriptorStream.WriteLine(" INDEX {0:D2} {1:D2}:{2:D2}:{3:D2}", 1, msf.minute, msf.second,
|
||||
msf.frame);
|
||||
}
|
||||
|
||||
descriptorStream.Flush();
|
||||
descriptorStream.Close();
|
||||
|
||||
IsWriting = false;
|
||||
ErrorMessage = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetGeometry(uint cylinders, uint heads, uint sectorsPerTrack)
|
||||
{
|
||||
ErrorMessage = "Unsupported feature";
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WriteSectorTag(byte[] data, ulong sectorAddress, SectorTagType tag)
|
||||
{
|
||||
if(!IsWriting)
|
||||
{
|
||||
ErrorMessage = "Tried to write on a non-writable image";
|
||||
return false;
|
||||
}
|
||||
|
||||
Track track =
|
||||
writingTracks.FirstOrDefault(trk => sectorAddress >= trk.TrackStartSector &&
|
||||
sectorAddress <= trk.TrackEndSector);
|
||||
|
||||
if(track.TrackSequence == 0)
|
||||
{
|
||||
ErrorMessage = $"Can't found track containing {sectorAddress}";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(tag)
|
||||
{
|
||||
case SectorTagType.CdTrackFlags:
|
||||
{
|
||||
if(data.Length != 1)
|
||||
{
|
||||
ErrorMessage = "Incorrect data size for track flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
trackFlags.Add((byte)track.TrackSequence, data[0]);
|
||||
return true;
|
||||
}
|
||||
case SectorTagType.CdTrackIsrc:
|
||||
{
|
||||
if(data != null) trackIsrcs.Add((byte)track.TrackSequence, Encoding.UTF8.GetString(data));
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
ErrorMessage = $"Unsupported tag type {tag}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteSectorsTag(byte[] data, ulong sectorAddress, uint length, SectorTagType tag)
|
||||
{
|
||||
return WriteSectorTag(data, sectorAddress, tag);
|
||||
}
|
||||
|
||||
public bool SetDumpHardware(List<DumpHardwareType> dumpHardware)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetCicmMetadata(CICMMetadataType metadata)
|
||||
{
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetMetadata(ImageInfo metadata)
|
||||
{
|
||||
discimage.Barcode = metadata.MediaBarcode;
|
||||
discimage.Comment = metadata.Comments;
|
||||
discimage.Title = metadata.MediaTitle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
100
DiscImageChef.DiscImages/CHD/CHD.cs
Normal file
100
DiscImageChef.DiscImages/CHD/CHD.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CHD.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disc image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Manages MAME Compressed Hunks of Data disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.CommonTypes.Enums;
|
||||
using DiscImageChef.CommonTypes.Interfaces;
|
||||
using DiscImageChef.CommonTypes.Structs;
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
// TODO: Implement PCMCIA support
|
||||
public partial class Chd : IMediaImage
|
||||
{
|
||||
/// <summary>"MComprHD"</summary>
|
||||
readonly byte[] chdTag = {0x4D, 0x43, 0x6F, 0x6D, 0x70, 0x72, 0x48, 0x44};
|
||||
uint bytesPerHunk;
|
||||
byte[] cis;
|
||||
byte[] expectedChecksum;
|
||||
uint hdrCompression;
|
||||
uint hdrCompression1;
|
||||
uint hdrCompression2;
|
||||
uint hdrCompression3;
|
||||
Dictionary<ulong, byte[]> hunkCache;
|
||||
byte[] hunkMap;
|
||||
ulong[] hunkTable;
|
||||
uint[] hunkTableSmall;
|
||||
byte[] identify;
|
||||
ImageInfo imageInfo;
|
||||
Stream imageStream;
|
||||
bool isCdrom;
|
||||
bool isGdrom;
|
||||
bool isHdd;
|
||||
uint mapVersion;
|
||||
int maxBlockCache;
|
||||
int maxSectorCache;
|
||||
Dictionary<ulong, uint> offsetmap;
|
||||
List<Partition> partitions;
|
||||
Dictionary<ulong, byte[]> sectorCache;
|
||||
uint sectorsPerHunk;
|
||||
bool swapAudio;
|
||||
uint totalHunks;
|
||||
Dictionary<uint, Track> tracks;
|
||||
|
||||
public Chd()
|
||||
{
|
||||
imageInfo = new ImageInfo
|
||||
{
|
||||
ReadableSectorTags = new List<SectorTagType>(),
|
||||
ReadableMediaTags = new List<MediaTagType>(),
|
||||
HasPartitions = false,
|
||||
HasSessions = false,
|
||||
Application = "MAME",
|
||||
Creator = null,
|
||||
Comments = null,
|
||||
MediaManufacturer = null,
|
||||
MediaModel = null,
|
||||
MediaSerialNumber = null,
|
||||
MediaBarcode = null,
|
||||
MediaPartNumber = null,
|
||||
MediaSequence = 0,
|
||||
LastMediaSequence = 0,
|
||||
DriveManufacturer = null,
|
||||
DriveModel = null,
|
||||
DriveSerialNumber = null,
|
||||
DriveFirmwareRevision = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
90
DiscImageChef.DiscImages/CHD/Constants.cs
Normal file
90
DiscImageChef.DiscImages/CHD/Constants.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Constants.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains constants for MAME Compressed Hunks of Data disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Chd
|
||||
{
|
||||
/// <summary>"GDDD"</summary>
|
||||
const uint HARD_DISK_METADATA = 0x47444444;
|
||||
/// <summary>"IDNT"</summary>
|
||||
const uint HARD_DISK_IDENT_METADATA = 0x49444E54;
|
||||
/// <summary>"KEY "</summary>
|
||||
const uint HARD_DISK_KEY_METADATA = 0x4B455920;
|
||||
/// <summary>"CIS "</summary>
|
||||
const uint PCMCIA_CIS_METADATA = 0x43495320;
|
||||
/// <summary>"CHCD"</summary>
|
||||
const uint CDROM_OLD_METADATA = 0x43484344;
|
||||
/// <summary>"CHTR"</summary>
|
||||
const uint CDROM_TRACK_METADATA = 0x43485452;
|
||||
/// <summary>"CHT2"</summary>
|
||||
const uint CDROM_TRACK_METADATA2 = 0x43485432;
|
||||
/// <summary>"CHGT"</summary>
|
||||
const uint GDROM_OLD_METADATA = 0x43484754;
|
||||
/// <summary>"CHGD"</summary>
|
||||
const uint GDROM_METADATA = 0x43484744;
|
||||
/// <summary>"AVAV"</summary>
|
||||
const uint AV_METADATA = 0x41564156;
|
||||
/// <summary>"AVLD"</summary>
|
||||
const uint AV_LASER_DISC_METADATA = 0x41564C44;
|
||||
|
||||
const string REGEX_METADATA_HDD =
|
||||
@"CYLS:(?<cylinders>\d+),HEADS:(?<heads>\d+),SECS:(?<sectors>\d+),BPS:(?<bps>\d+)";
|
||||
const string REGEX_METADATA_CDROM =
|
||||
@"TRACK:(?<track>\d+) TYPE:(?<track_type>\S+) SUBTYPE:(?<sub_type>\S+) FRAMES:(?<frames>\d+)";
|
||||
const string REGEX_METADATA_CDROM2 =
|
||||
@"TRACK:(?<track>\d+) TYPE:(?<track_type>\S+) SUBTYPE:(?<sub_type>\S+) FRAMES:(?<frames>\d+) PREGAP:(?<pregap>\d+) PGTYPE:(?<pgtype>\S+) PGSUB:(?<pgsub>\S+) POSTGAP:(?<postgap>\d+)";
|
||||
const string REGEX_METADATA_GDROM =
|
||||
@"TRACK:(?<track>\d+) TYPE:(?<track_type>\S+) SUBTYPE:(?<sub_type>\S+) FRAMES:(?<frames>\d+) PAD:(?<pad>\d+) PREGAP:(?<pregap>\d+) PGTYPE:(?<pgtype>\S+) PGSUB:(?<pgsub>\S+) POSTGAP:(?<postgap>\d+)";
|
||||
|
||||
const string TRACK_TYPE_MODE1 = "MODE1";
|
||||
const string TRACK_TYPE_MODE1_2K = "MODE1/2048";
|
||||
const string TRACK_TYPE_MODE1_RAW = "MODE1_RAW";
|
||||
const string TRACK_TYPE_MODE1_RAW_2K = "MODE1/2352";
|
||||
const string TRACK_TYPE_MODE2 = "MODE2";
|
||||
const string TRACK_TYPE_MODE2_2K = "MODE2/2336";
|
||||
const string TRACK_TYPE_MODE2_F1 = "MODE2_FORM1";
|
||||
const string TRACK_TYPE_MODE2_F1_2K = "MODE2/2048";
|
||||
const string TRACK_TYPE_MODE2_F2 = "MODE2_FORM2";
|
||||
const string TRACK_TYPE_MODE2_F2_2K = "MODE2/2324";
|
||||
const string TRACK_TYPE_MODE2_FM = "MODE2_FORM_MIX";
|
||||
const string TRACK_TYPE_MODE2_RAW = "MODE2_RAW";
|
||||
const string TRACK_TYPE_MODE2_RAW_2K = "MODE2/2352";
|
||||
const string TRACK_TYPE_AUDIO = "AUDIO";
|
||||
|
||||
const string SUB_TYPE_COOKED = "RW";
|
||||
const string SUB_TYPE_RAW = "RW_RAW";
|
||||
const string SUB_TYPE_NONE = "NONE";
|
||||
|
||||
const int MAX_CACHE_SIZE = 16777216;
|
||||
}
|
||||
}
|
||||
88
DiscImageChef.DiscImages/CHD/Enums.cs
Normal file
88
DiscImageChef.DiscImages/CHD/Enums.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
// /***************************************************************************
|
||||
// The Disc Image Chef
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Enums.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Disk image plugins.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains enumerations for MAME Compressed Hunks of Data disk images.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2018 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace DiscImageChef.DiscImages
|
||||
{
|
||||
public partial class Chd
|
||||
{
|
||||
enum ChdCompression : uint
|
||||
{
|
||||
None = 0,
|
||||
Zlib = 1,
|
||||
ZlibPlus = 2,
|
||||
Av = 3
|
||||
}
|
||||
|
||||
enum ChdFlags : uint
|
||||
{
|
||||
HasParent = 1,
|
||||
Writable = 2
|
||||
}
|
||||
|
||||
enum Chdv3EntryFlags : byte
|
||||
{
|
||||
/// <summary>Invalid</summary>
|
||||
Invalid = 0,
|
||||
/// <summary>Compressed with primary codec</summary>
|
||||
Compressed = 1,
|
||||
/// <summary>Uncompressed</summary>
|
||||
Uncompressed = 2,
|
||||
/// <summary>Use offset as data</summary>
|
||||
Mini = 3,
|
||||
/// <summary>Same as another hunk in file</summary>
|
||||
SelfHunk = 4,
|
||||
/// <summary>Same as another hunk in parent</summary>
|
||||
ParentHunk = 5,
|
||||
/// <summary>Compressed with secondary codec (FLAC)</summary>
|
||||
SecondCompressed = 6
|
||||
}
|
||||
|
||||
enum ChdOldTrackType : uint
|
||||
{
|
||||
Mode1 = 0,
|
||||
Mode1Raw,
|
||||
Mode2,
|
||||
Mode2Form1,
|
||||
Mode2Form2,
|
||||
Mode2FormMix,
|
||||
Mode2Raw,
|
||||
Audio
|
||||
}
|
||||
|
||||
enum ChdOldSubType : uint
|
||||
{
|
||||
Cooked = 0,
|
||||
Raw,
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user