From 736552f6d84cc3ace3f768e173aa9e3c13d129af Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sun, 24 Dec 2017 00:12:31 +0000 Subject: [PATCH] REFACTOR: Final cleanup of DiscImageChef.DiscImages. --- DiscImageChef.DiscImages/Alcohol120.cs | 282 ++-- DiscImageChef.DiscImages/Anex86.cs | 79 +- DiscImageChef.DiscImages/Apple2MG.cs | 180 ++- DiscImageChef.DiscImages/AppleDOS.cs | 27 +- DiscImageChef.DiscImages/AppleNIB.cs | 29 +- DiscImageChef.DiscImages/Apridisk.cs | 66 +- DiscImageChef.DiscImages/BLU.cs | 115 +- DiscImageChef.DiscImages/BlindWrite4.cs | 262 ++-- DiscImageChef.DiscImages/BlindWrite5.cs | 386 +++--- DiscImageChef.DiscImages/CDRDAO.cs | 413 +++--- DiscImageChef.DiscImages/CDRWin.cs | 367 ++--- DiscImageChef.DiscImages/CHD.cs | 985 +++++++------ DiscImageChef.DiscImages/CPCDSK.cs | 262 ++-- DiscImageChef.DiscImages/CisCopy.cs | 60 +- DiscImageChef.DiscImages/CloneCD.cs | 109 +- DiscImageChef.DiscImages/CopyQM.cs | 162 +-- DiscImageChef.DiscImages/D88.cs | 316 +++-- DiscImageChef.DiscImages/DART.cs | 68 +- DiscImageChef.DiscImages/DIM.cs | 36 +- DiscImageChef.DiscImages/DiscFerret.cs | 35 +- DiscImageChef.DiscImages/DiscJuggler.cs | 100 +- DiscImageChef.DiscImages/DiskCopy42.cs | 81 +- DiscImageChef.DiscImages/DriDiskCopy.cs | 184 ++- DiscImageChef.DiscImages/GDI.cs | 158 ++- DiscImageChef.DiscImages/HDCopy.cs | 168 ++- DiscImageChef.DiscImages/IMD.cs | 75 +- DiscImageChef.DiscImages/ImagePlugin.cs | 225 ++- DiscImageChef.DiscImages/KryoFlux.cs | 97 +- DiscImageChef.DiscImages/MaxiDisk.cs | 64 +- DiscImageChef.DiscImages/NDIF.cs | 262 ++-- DiscImageChef.DiscImages/NHDr0.cs | 40 +- DiscImageChef.DiscImages/Nero.cs | 1616 +++++++++++----------- DiscImageChef.DiscImages/Parallels.cs | 140 +- DiscImageChef.DiscImages/PartClone.cs | 118 +- DiscImageChef.DiscImages/Partimage.cs | 366 +++-- DiscImageChef.DiscImages/QCOW.cs | 146 +- DiscImageChef.DiscImages/QCOW2.cs | 170 ++- DiscImageChef.DiscImages/QED.cs | 154 +-- DiscImageChef.DiscImages/RayDIM.cs | 52 +- DiscImageChef.DiscImages/RsIde.cs | 47 +- DiscImageChef.DiscImages/SaveDskF.cs | 108 +- DiscImageChef.DiscImages/SuperCardPro.cs | 160 ++- DiscImageChef.DiscImages/T98.cs | 6 +- DiscImageChef.DiscImages/TeleDisk.cs | 231 ++-- DiscImageChef.DiscImages/UDIF.cs | 191 +-- DiscImageChef.DiscImages/UkvFdi.cs | 68 +- DiscImageChef.DiscImages/VDI.cs | 90 +- DiscImageChef.DiscImages/VHD.cs | 421 +++--- DiscImageChef.DiscImages/VHDX.cs | 501 ++++--- DiscImageChef.DiscImages/VMware.cs | 224 ++- DiscImageChef.DiscImages/Virtual98.cs | 40 +- DiscImageChef.DiscImages/ZZZRawImage.cs | 20 +- 52 files changed, 5203 insertions(+), 5359 deletions(-) diff --git a/DiscImageChef.DiscImages/Alcohol120.cs b/DiscImageChef.DiscImages/Alcohol120.cs index 6b04b538e..e42a8aace 100644 --- a/DiscImageChef.DiscImages/Alcohol120.cs +++ b/DiscImageChef.DiscImages/Alcohol120.cs @@ -49,131 +49,22 @@ namespace DiscImageChef.DiscImages { public class Alcohol120 : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct AlcoholHeader - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string 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; - } - #endregion Internal Structures - - #region Internal enumerations - [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 = 0xAC, - Mode2F2 = 0xAD, - Mode2F1Alt = 0xEC - } - - enum AlcoholSubchannelMode : byte - { - None = 0x00, - Interleaved = 0x08 - } - #endregion Internal enumerations - - #region Internal variables - Dictionary offsetmap; - List partitions; - Dictionary alcSessions; - Dictionary alcTracks; - Dictionary> alcToc; - Dictionary alcTrackExtras; AlcoholFooter alcFooter; Filter alcImage; + Dictionary alcSessions; + Dictionary> alcToc; + Dictionary alcTrackExtras; + Dictionary alcTracks; byte[] bca; - List sessions; - Stream imageStream; - byte[] fullToc; - bool isDvd; byte[] dmi; + byte[] fullToc; + Stream imageStream; + bool isDvd; + Dictionary offsetmap; + List partitions; byte[] pfi; - #endregion + List sessions; - #region Public Methods public Alcohol120() { Name = "Alcohol 120% Media Descriptor Structure"; @@ -410,10 +301,14 @@ namespace DiscImageChef.DiscImages if(alcFooter.filenameOffset > 0) { stream.Seek(alcFooter.filenameOffset, SeekOrigin.Begin); - byte[] filename = header.dpmOffset == 0 ? new byte[stream.Length - stream.Position] : new byte[header.dpmOffset - stream.Position]; + byte[] filename = header.dpmOffset == 0 + ? new byte[stream.Length - stream.Position] + : new byte[header.dpmOffset - stream.Position]; stream.Read(filename, 0, filename.Length); - alcFile = alcFooter.widechar == 1 ? Encoding.Unicode.GetString(filename) : Encoding.Default.GetString(filename); + alcFile = alcFooter.widechar == 1 + ? Encoding.Unicode.GetString(filename) + : Encoding.Default.GetString(filename); DicConsole.DebugWriteLine("Alcohol 120% plugin", "footer.filename = {0}", alcFile); } @@ -504,7 +399,8 @@ namespace DiscImageChef.DiscImages ImageInfo.MediaType = MediaType.HDDVDRW; break; case DiskCategory.Nintendo: - ImageInfo.MediaType = pfi0.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD; + ImageInfo.MediaType = + pfi0.Value.DiscSize == DVDSize.Eighty ? MediaType.GOD : MediaType.WOD; break; case DiskCategory.UMD: ImageInfo.MediaType = MediaType.UMD; @@ -597,7 +493,6 @@ namespace DiscImageChef.DiscImages Type = trk.mode.ToString() }; - partitions.Add(partition); ImageInfo.Sectors += extra.sectors; byteOffset += partition.Size; @@ -819,7 +714,8 @@ namespace DiscImageChef.DiscImages if(sectorAddress >= kvp.Value) foreach(AlcoholTrack track in alcTracks.Values) { - if(track.point != kvp.Key || !alcTrackExtras.TryGetValue(track.point, out AlcoholTrackExtra extra)) continue; + if(track.point != kvp.Key || + !alcTrackExtras.TryGetValue(track.point, out AlcoholTrackExtra extra)) continue; if(sectorAddress - kvp.Value < extra.sectors) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); @@ -834,7 +730,8 @@ namespace DiscImageChef.DiscImages if(sectorAddress >= kvp.Value) foreach(AlcoholTrack track in alcTracks.Values) { - if(track.point != kvp.Key || !alcTrackExtras.TryGetValue(track.point, out AlcoholTrackExtra extra)) continue; + if(track.point != kvp.Key || + !alcTrackExtras.TryGetValue(track.point, out AlcoholTrackExtra extra)) continue; if(sectorAddress - kvp.Value < extra.sectors) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); @@ -845,7 +742,8 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track) { - if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) + if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || + !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length + sectorAddress > alcExtra.sectors) @@ -937,7 +835,8 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag) { - if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) + if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || + !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length + sectorAddress > alcExtra.sectors) @@ -1273,7 +1172,8 @@ namespace DiscImageChef.DiscImages if(sectorAddress >= kvp.Value) foreach(AlcoholTrack alcTrack in alcTracks.Values) { - if(alcTrack.point != kvp.Key || !alcTrackExtras.TryGetValue(alcTrack.point, out AlcoholTrackExtra alcExtra)) continue; + if(alcTrack.point != kvp.Key || + !alcTrackExtras.TryGetValue(alcTrack.point, out AlcoholTrackExtra alcExtra)) continue; if(sectorAddress - kvp.Value < alcExtra.sectors) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); @@ -1284,7 +1184,8 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track) { - if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) + if(!alcTracks.TryGetValue((int)track, out AlcoholTrack alcTrack) || + !alcTrackExtras.TryGetValue((int)track, out AlcoholTrackExtra alcExtra)) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length + sectorAddress > alcExtra.sectors) @@ -1354,7 +1255,10 @@ namespace DiscImageChef.DiscImages 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(); + 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; @@ -1408,9 +1312,13 @@ namespace DiscImageChef.DiscImages foreach(AlcoholTrack alcTrack in alcTracks.Values) { - ushort sessionNo = (from ses in sessions where alcTrack.point >= ses.StartTrack || alcTrack.point <= ses.EndTrack select ses.SessionSequence).FirstOrDefault(); + ushort sessionNo = + (from ses in sessions + where alcTrack.point >= ses.StartTrack || alcTrack.point <= ses.EndTrack + select ses.SessionSequence).FirstOrDefault(); - if(!alcTrackExtras.TryGetValue(alcTrack.point, out AlcoholTrackExtra alcExtra) || session != sessionNo) continue; + if(!alcTrackExtras.TryGetValue(alcTrack.point, out AlcoholTrackExtra alcExtra) || + session != sessionNo) continue; Track dicTrack = new Track { @@ -1522,18 +1430,15 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion Public Methods - #region Private methods static ushort AlcoholTrackModeToBytesPerSector(AlcoholTrackMode trackMode) { switch(trackMode) @@ -1590,9 +1495,7 @@ namespace DiscImageChef.DiscImages default: return MediaType.Unknown; } } - #endregion Private methods - #region Unsupported features public override string GetImageApplicationVersion() { return ImageInfo.ImageApplicationVersion; @@ -1672,6 +1575,107 @@ namespace DiscImageChef.DiscImages { return ImageInfo.ImageCreator; } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct AlcoholHeader + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string 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; + } + + [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 = 0xAC, + Mode2F2 = 0xAD, + Mode2F1Alt = 0xEC + } + + enum AlcoholSubchannelMode : byte + { + None = 0x00, + Interleaved = 0x08 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Anex86.cs b/DiscImageChef.DiscImages/Anex86.cs index 016c2fae2..f75285e50 100644 --- a/DiscImageChef.DiscImages/Anex86.cs +++ b/DiscImageChef.DiscImages/Anex86.cs @@ -42,20 +42,8 @@ namespace DiscImageChef.DiscImages { public class Anex86 : ImagePlugin { - #region Internal structures - [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; - } - #endregion + Filter anexImageFilter; + Anex86Header fdihdr; public Anex86() { @@ -86,9 +74,6 @@ namespace DiscImageChef.DiscImages }; } - Anex86Header fdihdr; - Filter anexImageFilter; - public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -145,19 +130,25 @@ namespace DiscImageChef.DiscImages switch(fdihdr.spt) { case 8: - switch(fdihdr.heads) { - case 1: ImageInfo.MediaType = MediaType.DOS_525_SS_DD_8; + switch(fdihdr.heads) + { + case 1: + ImageInfo.MediaType = MediaType.DOS_525_SS_DD_8; break; - case 2: ImageInfo.MediaType = MediaType.DOS_525_DS_DD_8; + case 2: + ImageInfo.MediaType = MediaType.DOS_525_DS_DD_8; break; } break; case 9: - switch(fdihdr.heads) { - case 1: ImageInfo.MediaType = MediaType.DOS_525_SS_DD_9; + switch(fdihdr.heads) + { + case 1: + ImageInfo.MediaType = MediaType.DOS_525_SS_DD_9; break; - case 2: ImageInfo.MediaType = MediaType.DOS_525_DS_DD_9; + case 2: + ImageInfo.MediaType = MediaType.DOS_525_DS_DD_9; break; } @@ -232,10 +223,13 @@ namespace DiscImageChef.DiscImages switch(fdihdr.spt) { case 16: - switch(fdihdr.heads) { - case 1: ImageInfo.MediaType = MediaType.NEC_525_SS; + switch(fdihdr.heads) + { + case 1: + ImageInfo.MediaType = MediaType.NEC_525_SS; break; - case 2: ImageInfo.MediaType = MediaType.NEC_525_DS; + case 2: + ImageInfo.MediaType = MediaType.NEC_525_DS; break; } @@ -247,19 +241,25 @@ namespace DiscImageChef.DiscImages switch(fdihdr.spt) { case 8: - switch(fdihdr.heads) { - case 1: ImageInfo.MediaType = MediaType.DOS_35_SS_DD_8; + switch(fdihdr.heads) + { + case 1: + ImageInfo.MediaType = MediaType.DOS_35_SS_DD_8; break; - case 2: ImageInfo.MediaType = MediaType.DOS_35_DS_DD_8; + case 2: + ImageInfo.MediaType = MediaType.DOS_35_DS_DD_8; break; } break; case 9: - switch(fdihdr.heads) { - case 1: ImageInfo.MediaType = MediaType.DOS_35_SS_DD_9; + switch(fdihdr.heads) + { + case 1: + ImageInfo.MediaType = MediaType.DOS_35_SS_DD_9; break; - case 2: ImageInfo.MediaType = MediaType.DOS_35_DS_DD_9; + case 2: + ImageInfo.MediaType = MediaType.DOS_35_DS_DD_9; break; } @@ -408,7 +408,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -569,6 +568,18 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [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; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Apple2MG.cs b/DiscImageChef.DiscImages/Apple2MG.cs index 18dedbe6f..25cd93458 100644 --- a/DiscImageChef.DiscImages/Apple2MG.cs +++ b/DiscImageChef.DiscImages/Apple2MG.cs @@ -43,112 +43,36 @@ namespace DiscImageChef.DiscImages { public class Apple2Mg : ImagePlugin { - #region Internal Structures - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - struct A2ImgHeader - { - /// - /// Offset 0x00, magic - /// - public uint Magic; - /// - /// Offset 0x04, disk image creator ID - /// - public uint Creator; - /// - /// Offset 0x08, header size, constant 0x0040 - /// - public ushort HeaderSize; - /// - /// Offset 0x0A, disk image version - /// - public ushort Version; - /// - /// Offset 0x0C, disk image format - /// - public uint ImageFormat; - /// - /// Offset 0x10, flags and volume number - /// - public uint Flags; - /// - /// Offset 0x14, blocks for ProDOS, 0 otherwise - /// - public uint Blocks; - /// - /// Offset 0x18, offset to data - /// - public uint DataOffset; - /// - /// Offset 0x1C, data size in bytes - /// - public uint DataSize; - /// - /// Offset 0x20, offset to optional comment - /// - public uint CommentOffset; - /// - /// Offset 0x24, length of optional comment - /// - public uint CommentSize; - /// - /// Offset 0x28, offset to creator specific chunk - /// - public uint CreatorSpecificOffset; - /// - /// Offset 0x2C, creator specific chunk size - /// - public uint CreatorSpecificSize; - /// - /// Offset 0x30, reserved, should be zero - /// - public uint Reserved1; - /// - /// Offset 0x34, reserved, should be zero - /// - public uint Reserved2; - /// - /// Offset 0x38, reserved, should be zero - /// - public uint Reserved3; - /// - /// Offset 0x3C, reserved, should be zero - /// - public uint Reserved4; - } - #endregion - - #region Internal Constants /// - /// Magic number, "2IMG" + /// Magic number, "2IMG" /// const uint MAGIC = 0x474D4932; /// - /// Disk image created by ASIMOV2, "!nfc" + /// Disk image created by ASIMOV2, "!nfc" /// const uint CREATOR_ASIMOV = 0x63666E21; /// - /// Disk image created by Bernie ][ the Rescue, "B2TR" + /// Disk image created by Bernie ][ the Rescue, "B2TR" /// const uint CREATOR_BERNIE = 0x52543242; /// - /// Disk image created by Catakig, "CTKG" + /// Disk image created by Catakig, "CTKG" /// const uint CREATOR_CATAKIG = 0x474B5443; /// - /// Disk image created by Sheppy's ImageMaker, "ShIm" + /// Disk image created by Sheppy's ImageMaker, "ShIm" /// const uint CREATOR_SHEPPY = 0x6D496853; /// - /// Disk image created by Sweet16, "WOOF" + /// Disk image created by Sweet16, "WOOF" /// const uint CREATOR_SWEET = 0x464F4F57; /// - /// Disk image created by XGS, "XGS!" + /// Disk image created by XGS, "XGS!" /// const uint CREATOR_XGS = 0x21534758; /// - /// Disk image created by CiderPress, "CdrP" + /// Disk image created by CiderPress, "CdrP" /// const uint CREATOR_CIDER = 0x50726443; @@ -159,12 +83,9 @@ namespace DiscImageChef.DiscImages const uint LOCKED_DISK = 0x80000000; const uint VALID_VOLUME_NUMBER = 0x00000100; const uint VOLUME_NUMBER_MASK = 0x000000FF; - #endregion - - #region Internal variables - A2ImgHeader imageHeader; + Filter a2MgImageFilter; - #endregion + A2ImgHeader imageHeader; public Apple2Mg() { @@ -291,9 +212,11 @@ namespace DiscImageChef.DiscImages if(imageHeader.DataSize == 0 && imageHeader.Blocks == 0 && imageHeader.ImageFormat != PRODOS_SECTOR_ORDER) return false; - switch(imageHeader.ImageFormat) { + switch(imageHeader.ImageFormat) + { case PRODOS_SECTOR_ORDER when imageHeader.Blocks == 0: return false; - case PRODOS_SECTOR_ORDER: imageHeader.DataSize = imageHeader.Blocks * 512; + case PRODOS_SECTOR_ORDER: + imageHeader.DataSize = imageHeader.Blocks * 512; break; default: if(imageHeader.Blocks == 0 && imageHeader.DataSize != 0) @@ -502,7 +425,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -663,6 +585,78 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [SuppressMessage("ReSharper", "NotAccessedField.Local")] + struct A2ImgHeader + { + /// + /// Offset 0x00, magic + /// + public uint Magic; + /// + /// Offset 0x04, disk image creator ID + /// + public uint Creator; + /// + /// Offset 0x08, header size, constant 0x0040 + /// + public ushort HeaderSize; + /// + /// Offset 0x0A, disk image version + /// + public ushort Version; + /// + /// Offset 0x0C, disk image format + /// + public uint ImageFormat; + /// + /// Offset 0x10, flags and volume number + /// + public uint Flags; + /// + /// Offset 0x14, blocks for ProDOS, 0 otherwise + /// + public uint Blocks; + /// + /// Offset 0x18, offset to data + /// + public uint DataOffset; + /// + /// Offset 0x1C, data size in bytes + /// + public uint DataSize; + /// + /// Offset 0x20, offset to optional comment + /// + public uint CommentOffset; + /// + /// Offset 0x24, length of optional comment + /// + public uint CommentSize; + /// + /// Offset 0x28, offset to creator specific chunk + /// + public uint CreatorSpecificOffset; + /// + /// Offset 0x2C, creator specific chunk size + /// + public uint CreatorSpecificSize; + /// + /// Offset 0x30, reserved, should be zero + /// + public uint Reserved1; + /// + /// Offset 0x34, reserved, should be zero + /// + public uint Reserved2; + /// + /// Offset 0x38, reserved, should be zero + /// + public uint Reserved3; + /// + /// Offset 0x3C, reserved, should be zero + /// + public uint Reserved4; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/AppleDOS.cs b/DiscImageChef.DiscImages/AppleDOS.cs index 7e6489065..96857eae3 100644 --- a/DiscImageChef.DiscImages/AppleDOS.cs +++ b/DiscImageChef.DiscImages/AppleDOS.cs @@ -41,10 +41,8 @@ namespace DiscImageChef.DiscImages // Checked using several images and strings inside Apple's DiskImages.framework public class AppleDos : ImagePlugin { - #region Internal variables - byte[] deinterleaved; - string extension; - #endregion + readonly int[] dosOffsets = {0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15}; + readonly int[] prodosOffsets = {0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15}; public AppleDos() { @@ -79,14 +77,9 @@ namespace DiscImageChef.DiscImages { extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower(); - if(imageFilter.GetDataForkLength() == 143360 && (extension == ".po" || extension == ".do")) return true; - - return false; + return imageFilter.GetDataForkLength() == 143360 && (extension == ".po" || extension == ".do"); } - readonly int[] dosOffsets = {0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15}; - readonly int[] prodosOffsets = {0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15}; - public override bool OpenImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -104,8 +97,7 @@ namespace DiscImageChef.DiscImages 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); + Array.Copy(tmp, t * 16 * 256 + s * 256, deinterleaved, t * 16 * 256 + offsets[s] * 256, 256); } ImageInfo.SectorSize = 256; @@ -165,9 +157,7 @@ namespace DiscImageChef.DiscImages public override string GetImageFormat() { - if(extension == ".po") return "Apple ][ Interleaved Disk Image (ProDOS order)"; - - return "Apple ][ Interleaved Disk Image (DOS order)"; + return extension == ".po" ? "Apple ][ Interleaved Disk Image (ProDOS order)" : "Apple ][ Interleaved Disk Image (DOS order)"; } public override DateTime GetImageCreationTime() @@ -267,6 +257,11 @@ namespace DiscImageChef.DiscImages throw new FeatureUnsupportedImageException("Feature not supported by image format"); } + #region Internal variables + byte[] deinterleaved; + string extension; + #endregion + #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { @@ -382,6 +377,6 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + #endregion } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/AppleNIB.cs b/DiscImageChef.DiscImages/AppleNIB.cs index 57544f8c8..a25d8f7f8 100644 --- a/DiscImageChef.DiscImages/AppleNIB.cs +++ b/DiscImageChef.DiscImages/AppleNIB.cs @@ -44,26 +44,24 @@ namespace DiscImageChef.DiscImages // TODO: Checksum sectors public class AppleNib : ImagePlugin { - Dictionary longSectors; - Dictionary cookedSectors; - Dictionary addressFields; - - readonly ulong[] dosSkewing = {0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15}; - readonly ulong[] proDosSkewing = {0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15}; - - readonly byte[] pascal_sign = {0x08, 0xA5, 0x0F, 0x29}; - readonly byte[] pascal2_sign = {0xFF, 0xA2, 0x00, 0x8E}; - readonly byte[] dos_sign = {0xA2, 0x02, 0x8E, 0x52}; - readonly byte[] sos_sign = {0xC9, 0x20, 0xF0, 0x3E}; readonly byte[] apple3_sign = {0x8D, 0xD0, 0x03, 0x4C, 0xC7, 0xA4}; readonly byte[] cpm_sign = {0xA2, 0x55, 0xA9, 0x00, 0x9D, 0x00, 0x0D, 0xCA}; - readonly byte[] prodos_string = {0x50, 0x52, 0x4F, 0x44, 0x4F, 0x53}; - readonly byte[] pascal_string = {0x53, 0x59, 0x53, 0x54, 0x45, 0x2E, 0x41, 0x50, 0x50, 0x4C, 0x45}; + 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 addressFields; + Dictionary cookedSectors; + Dictionary longSectors; public AppleNib() { @@ -125,7 +123,8 @@ namespace DiscImageChef.DiscImages int spt = 0; bool allTracksEqual = true; - for(int i = 1; i < tracks.Count; i++) allTracksEqual &= tracks[i - 1].sectors.Length == tracks[i].sectors.Length; + for(int i = 1; i < tracks.Count; i++) + allTracksEqual &= tracks[i - 1].sectors.Length == tracks[i].sectors.Length; if(allTracksEqual) spt = tracks[0].sectors.Length; @@ -417,7 +416,6 @@ namespace DiscImageChef.DiscImages return ms.ToArray(); } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -558,6 +556,5 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Apridisk.cs b/DiscImageChef.DiscImages/Apridisk.cs index 543e25bad..88da8f0e0 100644 --- a/DiscImageChef.DiscImages/Apridisk.cs +++ b/DiscImageChef.DiscImages/Apridisk.cs @@ -43,23 +43,6 @@ namespace DiscImageChef.DiscImages { public class Apridisk : ImagePlugin { - #region Internal enumerations - enum RecordType : uint - { - Deleted = 0xE31D0000, - Sector = 0xE31D0001, - Comment = 0xE31D0002, - Creator = 0xE31D0003 - } - - enum CompressType : ushort - { - Uncompresed = 0x9E90, - Compressed = 0x3E5A - } - #endregion - - #region Internal constants readonly byte[] signature = { 0x41, 0x43, 0x54, 0x20, 0x41, 0x70, 0x72, 0x69, 0x63, 0x6F, 0x74, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x69, @@ -71,21 +54,6 @@ namespace DiscImageChef.DiscImages 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - #endregion - - #region Internal structures - [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; - } - #endregion // Cylinder by head, sector data matrix byte[][][][] sectorsData; @@ -152,7 +120,8 @@ namespace DiscImageChef.DiscImages stream.Read(recB, 0, recordSize); GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned); - ApridiskRecord record = (ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord)); + ApridiskRecord record = + (ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord)); handle.Free(); switch(record.type) @@ -241,7 +210,8 @@ namespace DiscImageChef.DiscImages stream.Read(recB, 0, recordSize); GCHandle handle = GCHandle.Alloc(recB, GCHandleType.Pinned); - ApridiskRecord record = (ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord)); + ApridiskRecord record = + (ApridiskRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ApridiskRecord)); handle.Free(); switch(record.type) @@ -450,7 +420,6 @@ namespace DiscImageChef.DiscImages return (cylinder, head, sector); } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -611,6 +580,31 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + 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; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/BLU.cs b/DiscImageChef.DiscImages/BLU.cs index 17da92949..04e845d39 100644 --- a/DiscImageChef.DiscImages/BLU.cs +++ b/DiscImageChef.DiscImages/BLU.cs @@ -41,30 +41,15 @@ namespace DiscImageChef.DiscImages { public class Blu : ImagePlugin { - #region Internal Structures - struct BluHeader - { - public byte[] DeviceName; - public uint DeviceType; - public uint DeviceBlocks; - public ushort BytesPerBlock; - } - #endregion Internal Structures - - #region Internal Constants const string PROFILE_NAME = "PROFILE "; const string PROFILE10_NAME = "PROFILE 10 "; const string WIDGET_NAME = "WIDGET-10 "; const string PRIAM_NAME = "PRIAMDTATOWER"; - #endregion Internal Constants - - #region Internal variables - BluHeader imageHeader; Filter bluImageFilter; int bptag; - #endregion Internal variables - #region Public methods + BluHeader imageHeader; + public Blu() { Name = "Basic Lisa Utility"; @@ -114,9 +99,7 @@ namespace DiscImageChef.DiscImages for(int i = 0; i < 0xD; i++) if(tmpHdr.DeviceName[i] < 0x20) return false; - if((tmpHdr.BytesPerBlock & 0xFE00) != 0x200) return false; - - return true; + return (tmpHdr.BytesPerBlock & 0xFE00) == 0x200; } public override bool OpenImage(Filter imageFilter) @@ -177,7 +160,8 @@ namespace DiscImageChef.DiscImages ImageInfo.SectorsPerTrack = 16; break; case PRIAM_NAME: - ImageInfo.MediaType = ImageInfo.Sectors == 0x022C7C ? MediaType.PriamDataTower : MediaType.GENERIC_HDD; + ImageInfo.MediaType = + ImageInfo.Sectors == 0x022C7C ? MediaType.PriamDataTower : MediaType.GENERIC_HDD; // This values are invented... ImageInfo.Cylinders = 419; ImageInfo.Heads = 4; @@ -208,45 +192,6 @@ namespace DiscImageChef.DiscImages return true; } - #region Verification, should add tag checksum checks - public override bool? VerifySector(ulong sectorAddress) - { - return null; - } - - public override bool? VerifySector(ulong sectorAddress, uint track) - { - return null; - } - - public override bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, - out List unknownLbas) - { - failingLbas = new List(); - unknownLbas = new List(); - - for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i); - - return null; - } - - public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, - out List unknownLbas) - { - failingLbas = new List(); - unknownLbas = new List(); - - for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i); - - return null; - } - - public override bool? VerifyMediaImage() - { - return null; - } - #endregion Verification, should add tag checksum checks - public override bool ImageHasPartitions() { return ImageInfo.ImageHasPartitions; @@ -398,9 +343,7 @@ namespace DiscImageChef.DiscImages { return ImageInfo.MediaType; } - #endregion Public methods - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -520,6 +463,52 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + struct BluHeader + { + public byte[] DeviceName; + public uint DeviceType; + public uint DeviceBlocks; + public ushort BytesPerBlock; + } + + #region Verification, should add tag checksum checks + public override bool? VerifySector(ulong sectorAddress) + { + return null; + } + + public override bool? VerifySector(ulong sectorAddress, uint track) + { + return null; + } + + public override bool? VerifySectors(ulong sectorAddress, uint length, out List failingLbas, + out List unknownLbas) + { + failingLbas = new List(); + unknownLbas = new List(); + + for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i); + + return null; + } + + public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, + out List unknownLbas) + { + failingLbas = new List(); + unknownLbas = new List(); + + for(ulong i = sectorAddress; i < sectorAddress + length; i++) unknownLbas.Add(i); + + return null; + } + + public override bool? VerifyMediaImage() + { + return null; + } + #endregion Verification, should add tag checksum checks } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/BlindWrite4.cs b/DiscImageChef.DiscImages/BlindWrite4.cs index 87bae2255..c533b04f8 100644 --- a/DiscImageChef.DiscImages/BlindWrite4.cs +++ b/DiscImageChef.DiscImages/BlindWrite4.cs @@ -46,148 +46,23 @@ namespace DiscImageChef.DiscImages { public class BlindWrite4 : ImagePlugin { - #region Internal Constants /// "BLINDWRITE TOC FILE" readonly byte[] bw4Signature = { 0x42, 0x4C, 0x49, 0x4E, 0x44, 0x57, 0x52, 0x49, 0x54, 0x45, 0x20, 0x54, 0x4F, 0x43, 0x20, 0x46, 0x49, 0x4C, 0x45 }; - #endregion Internal Constants - - #region Internal Structures - 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 Filter DataFilter; - public Filter 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; - } - #endregion Internal Structures - - #region Internal enumerations - enum Bw4TrackType : byte - { - Audio = 0, - Mode1 = 1, - Mode2 = 2 - } - #endregion Internal enumerations - - #region Internal variables - Bw4Header header; List bwTracks; - List tracks; + Filter dataFilter, subFilter; + + Bw4Header header; + Stream imageStream; Dictionary offsetmap; List partitions; List sessions; - Filter dataFilter, subFilter; - Stream imageStream; Dictionary trackFlags; - #endregion Internal variables + List tracks; - #region Public Methods public BlindWrite4() { Name = "BlindWrite 4"; @@ -1018,7 +893,6 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) { dicTrack = bwTrack; @@ -1202,7 +1076,6 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) { dicTrack = bwTrack; @@ -1330,9 +1203,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, @@ -1361,18 +1233,15 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion Public Methods - #region Unsupported features public override string GetImageApplicationVersion() { return ImageInfo.ImageApplicationVersion; @@ -1452,6 +1321,121 @@ namespace DiscImageChef.DiscImages { return ImageInfo.ImageCreator; } - #endregion Unsupported features + + 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 Filter DataFilter; + public Filter 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 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/BlindWrite5.cs b/DiscImageChef.DiscImages/BlindWrite5.cs index 6b437cd8f..2a203b379 100644 --- a/DiscImageChef.DiscImages/BlindWrite5.cs +++ b/DiscImageChef.DiscImages/BlindWrite5.cs @@ -51,165 +51,36 @@ namespace DiscImageChef.DiscImages { public class BlindWrite5 : ImagePlugin { - #region Internal Constants - /// "BWT5 STREAM SIGN" - readonly byte[] bw5Signature = - {0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x53, 0x49, 0x47, 0x4E}; /// "BWT5 STREAM FOOT" readonly byte[] bw5Footer = {0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x46, 0x4F, 0x4F, 0x54}; - #endregion Internal Constants - - #region Internal enumerations - 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 - } - #endregion Internal enumerations - - #region Internal Structures - [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 unknown4; - 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 Filter FileFilter; - public string FilePath; - public TrackSubchannelType Subchannel; - public long SectorSize; - public int StartLba; - public int Sectors; - } - #endregion Internal Structures - - #region Internal variables - Bw5Header header; - byte[] mode2A; - byte[] unkBlock; - byte[] pma; + /// "BWT5 STREAM SIGN" + readonly byte[] bw5Signature = + {0x42, 0x57, 0x54, 0x35, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4D, 0x20, 0x53, 0x49, 0x47, 0x4E}; byte[] atip; - byte[] cdtext; byte[] bca; - byte[] dmi; - byte[] pfi; - byte[] discInformation; - string dataPath; - List dataFiles; List bwSessions; + byte[] cdtext; + List dataFiles; + string dataPath; + byte[] discInformation; + byte[] dmi; byte[] dpm; - List sessions; - List tracks; - List partitions; List filePaths; byte[] fullToc; - Dictionary offsetmap; - Dictionary trackFlags; - Stream imageStream; - #endregion Internal variables - #region Public Methods + Bw5Header header; + Stream imageStream; + byte[] mode2A; + Dictionary offsetmap; + List partitions; + byte[] pfi; + byte[] pma; + List sessions; + Dictionary trackFlags; + List tracks; + byte[] unkBlock; + public BlindWrite5() { Name = "BlindWrite 5"; @@ -359,8 +230,7 @@ namespace DiscImageChef.DiscImages ATIP.CDATIP? decodedAtip = ATIP.Decode(atip); if(decodedAtip.HasValue) - DicConsole.DebugWriteLine("BlindWrite5 plugin", "ATIP: {0}", - ATIP.Prettify(decodedAtip)); + DicConsole.DebugWriteLine("BlindWrite5 plugin", "ATIP: {0}", ATIP.Prettify(decodedAtip)); else atip = null; } @@ -741,13 +611,17 @@ namespace DiscImageChef.DiscImages long sectorSize = dataFile.Length / dataFile.Sectors; if(sectorSize > 2352) - switch(sectorSize - 2352) { - case 16: chars.Subchannel = TrackSubchannelType.Q16Interleaved; + switch(sectorSize - 2352) + { + case 16: + chars.Subchannel = TrackSubchannelType.Q16Interleaved; break; - case 96: chars.Subchannel = TrackSubchannelType.PackedInterleaved; + case 96: + chars.Subchannel = TrackSubchannelType.PackedInterleaved; break; default: - DicConsole.ErrorWriteLine("BlindWrite5 found unknown subchannel size: {0}", sectorSize - 2352); + DicConsole.ErrorWriteLine("BlindWrite5 found unknown subchannel size: {0}", + sectorSize - 2352); return false; } else chars.Subchannel = TrackSubchannelType.None; @@ -872,7 +746,9 @@ namespace DiscImageChef.DiscImages track.TrackEndSector = (ulong)(trk.sectors + trk.startLba); foreach(DataFileCharacteristics chars in filePaths.Where(chars => trk.startLba >= chars.StartLba && - trk.startLba + trk.sectors <= chars.StartLba + chars.Sectors)) { + trk.startLba + trk.sectors <= + chars.StartLba + chars.Sectors)) + { track.TrackFilter = chars.FileFilter; track.TrackFile = chars.FileFilter.GetFilename(); if(trk.startLba >= 0) @@ -1084,8 +960,10 @@ namespace DiscImageChef.DiscImages { PMA.CDPMA pma0 = PMA.Decode(pma).Value; - foreach(uint id in from descriptor in pma0.PMADescriptors where descriptor.ADR == 2 select (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame)) ImageInfo.MediaSerialNumber = - $"{id & 0x00FFFFFF:X6}"; + foreach(uint id in from descriptor in pma0.PMADescriptors + where descriptor.ADR == 2 + select (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame)) + ImageInfo.MediaSerialNumber = $"{id & 0x00FFFFFF:X6}"; } if(atip != null) @@ -1111,14 +989,15 @@ namespace DiscImageChef.DiscImages } if(isBd && ImageInfo.Sectors > 24438784) - { - switch(ImageInfo.MediaType) { - case MediaType.BDR: ImageInfo.MediaType = MediaType.BDRXL; + switch(ImageInfo.MediaType) + { + case MediaType.BDR: + ImageInfo.MediaType = MediaType.BDRXL; break; - case MediaType.BDRE: ImageInfo.MediaType = MediaType.BDREXL; + case MediaType.BDRE: + ImageInfo.MediaType = MediaType.BDREXL; break; } - } DicConsole.DebugWriteLine("BlindWrite5 plugin", "ImageInfo.mediaType = {0}", ImageInfo.MediaType); @@ -1244,14 +1123,28 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -1264,7 +1157,8 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSequence = 0; - foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) { + foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) + { dicTrack = bwTrack; break; } @@ -1276,7 +1170,11 @@ namespace DiscImageChef.DiscImages throw new ArgumentOutOfRangeException(nameof(length), $"Requested more sectors ({length + sectorAddress}) than present in track ({dicTrack.TrackEndSector}), won't cross tracks"); - foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => (long)sectorAddress >= _chars.StartLba && length < (ulong)_chars.Sectors - sectorAddress)) { + foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => + (long)sectorAddress >= _chars.StartLba && + length < (ulong)_chars.Sectors - + sectorAddress)) + { chars = _chars; break; } @@ -1378,7 +1276,8 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSequence = 0; - foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) { + foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) + { dicTrack = bwTrack; break; } @@ -1390,7 +1289,11 @@ namespace DiscImageChef.DiscImages throw new ArgumentOutOfRangeException(nameof(length), $"Requested more sectors ({length + sectorAddress}) than present in track ({dicTrack.TrackEndSector}), won't cross tracks"); - foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => (long)sectorAddress >= _chars.StartLba && length < (ulong)_chars.Sectors - sectorAddress)) { + foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => + (long)sectorAddress >= _chars.StartLba && + length < (ulong)_chars.Sectors - + sectorAddress)) + { chars = _chars; break; } @@ -1661,7 +1564,14 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -1674,7 +1584,8 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSequence = 0; - foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) { + foreach(Track bwTrack in tracks.Where(bwTrack => bwTrack.TrackSequence == track)) + { dicTrack = bwTrack; break; } @@ -1686,7 +1597,11 @@ namespace DiscImageChef.DiscImages throw new ArgumentOutOfRangeException(nameof(length), $"Requested more sectors ({length + sectorAddress}) than present in track ({dicTrack.TrackEndSector}), won't cross tracks"); - foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => (long)sectorAddress >= _chars.StartLba && length < (ulong)_chars.Sectors - sectorAddress)) { + foreach(DataFileCharacteristics _chars in filePaths.Where(_chars => + (long)sectorAddress >= _chars.StartLba && + length < (ulong)_chars.Sectors - + sectorAddress)) + { chars = _chars; break; } @@ -1840,9 +1755,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List failingLbas, @@ -1871,16 +1785,134 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion Public Methods + + 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 unknown4; + 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 Filter FileFilter; + public string FilePath; + public TrackSubchannelType Subchannel; + public long SectorSize; + public int StartLba; + public int Sectors; + } #region Private methods static TrackType BlindWriteTrackTypeToTrackType(Bw5TrackType trackType) diff --git a/DiscImageChef.DiscImages/CDRDAO.cs b/DiscImageChef.DiscImages/CDRDAO.cs index 02e1a5101..c3b7f9333 100644 --- a/DiscImageChef.DiscImages/CDRDAO.cs +++ b/DiscImageChef.DiscImages/CDRDAO.cs @@ -48,106 +48,6 @@ namespace DiscImageChef.DiscImages // TODO: Doesn't support silences that are not in files public class Cdrdao : ImagePlugin { - #region Internal structures - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - struct CdrdaoTrackFile - { - /// Track # - public uint Sequence; - /// Filter of file containing track - public Filter Datafilter; - /// Path of file containing track - public string Datafile; - /// Offset of track start in file - public ulong Offset; - /// Type of file - public string Filetype; - } - -#pragma warning disable 169 - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - struct CdrdaoTrack - { - /// Track # - public uint Sequence; - /// Track title (from CD-Text) - public string Title; - /// Track genre (from CD-Text) - public string Genre; - /// Track arranger (from CD-Text) - public string Arranger; - /// Track composer (from CD-Text) - public string Composer; - /// Track performer (from CD-Text) - public string Performer; - /// Track song writer (from CD-Text) - public string Songwriter; - /// Track ISRC - public string Isrc; - /// Disk provider's message (from CD-Text) - public string Message; - /// File struct for this track - public CdrdaoTrackFile Trackfile; - /// Indexes on this track - public Dictionary Indexes; - /// Track pre-gap in sectors - public ulong Pregap; - /// Track post-gap in sectors - public ulong Postgap; - /// Digical Copy Permitted - public bool FlagDcp; - /// Track is quadraphonic - public bool Flag_4Ch; - /// Track has preemphasis - public bool FlagPre; - /// Bytes per sector - public ushort Bps; - /// Sectors in track - public ulong Sectors; - /// Starting sector in track - public ulong StartSector; - /// Track type - public string Tracktype; - public bool Subchannel; - public bool Packedsubchannel; - } - - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - struct CdrdaoDisc - { - /// Disk title (from CD-Text) - public string Title; - /// Disk genre (from CD-Text) - public string Genre; - /// Disk arranger (from CD-Text) - public string Arranger; - /// Disk composer (from CD-Text) - public string Composer; - /// Disk performer (from CD-Text) - public string Performer; - /// Disk song writer (from CD-Text) - public string Songwriter; - /// Disk provider's message (from CD-Text) - public string Message; - /// Media catalog number - public string Mcn; - /// Disk type - public MediaType Disktype; - /// Disk type string - public string Disktypestr; - /// Disk CDDB ID - public string DiskId; - /// Disk UPC/EAN - public string Barcode; - /// Tracks - public List Tracks; - /// Disk comment - public string Comment; - } -#pragma warning restore 169 - #endregion Internal structures - - #region Internal consts /// Audio track, 2352 bytes/sector const string CDRDAO_TRACK_TYPE_AUDIO = "AUDIO"; /// Mode 1 track, cooked, 2048 bytes/sector @@ -164,59 +64,53 @@ namespace DiscImageChef.DiscImages const string CDRDAO_TRACK_TYPE_MODE2_MIX = "MODE2_FORM_MIX"; /// Mode 2 track, raw, 2352 bytes/sector const string CDRDAO_TRACK_TYPE_MODE2_RAW = "MODE2_RAW"; - #endregion Internal consts - #region Internal variables + const string REGEX_COMMENT = "^\\s*\\/{2}(?.+)$"; + const string REGEX_COPY = "^\\s*(?NO)?\\s*COPY"; + const string REGEX_DISCTYPE = "^\\s*(?(CD_DA|CD_ROM_XA|CD_ROM|CD_I))"; + const string REGEX_EMPHASIS = "^\\s*(?NO)?\\s*PRE_EMPHASIS"; + const string REGEX_FILE_AUDIO = + "^\\s*(AUDIO)?FILE\\s*\"(?.+)\"\\s*(#(?\\d+))?\\s*((?[\\d]+:[\\d]+:[\\d]+)|(?\\d+))\\s*(?[\\d]+:[\\d]+:[\\d]+)?" + ; + const string REGEX_FILE_DATA = + "^\\s*DATAFILE\\s*\"(?.+)\"\\s*(#(?\\d+))?\\s*(?[\\d]+:[\\d]+:[\\d]+)?"; + const string REGEX_INDEX = "^\\s*INDEX\\s*(?
\\d+:\\d+:\\d+)"; + const string REGEX_ISRC = "^\\s*ISRC\\s*\"(?[A-Z0-9]{5,5}[0-9]{7,7})\""; + const string REGEX_MCN = "^\\s*CATALOG\\s*\"(?[\\d]{13,13})\""; + const string REGEX_PREGAP = "^\\s*START\\s*(?
\\d+:\\d+:\\d+)?"; + const string REGEX_STEREO = "^\\s*(?(TWO|FOUR))_CHANNEL_AUDIO"; + const string REGEX_TRACK = + "^\\s*TRACK\\s*(?(AUDIO|MODE1_RAW|MODE1|MODE2_FORM1|MODE2_FORM2|MODE2_FORM_MIX|MODE2_RAW|MODE2))\\s*(?(RW_RAW|RW))?" + ; + const string REGEX_ZERO_AUDIO = "^\\s*SILENCE\\s*(?\\d+:\\d+:\\d+)"; + const string REGEX_ZERO_DATA = "^\\s*ZERO\\s*(?\\d+:\\d+:\\d+)"; + const string REGEX_ZERO_PREGAP = "^\\s*PREGAP\\s*(?\\d+:\\d+:\\d+)"; + + // CD-Text + const string REGEX_ARRANGER = "^\\s*ARRANGER\\s*\"(?.+)\""; + const string REGEX_COMPOSER = "^\\s*COMPOSER\\s*\"(?.+)\""; + const string REGEX_DISC_ID = "^\\s*DISC_ID\\s*\"(?.+)\""; + const string REGEX_MESSAGE = "^\\s*MESSAGE\\s*\"(?.+)\""; + const string REGEX_PERFORMER = "^\\s*PERFORMER\\s*\"(?.+)\""; + const string REGEX_SONGWRITER = "^\\s*SONGWRITER\\s*\"(?.+)\""; + const string REGEX_TITLE = "^\\s*TITLE\\s*\"(?.+)\""; + 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+)"; + Filter cdrdaoFilter; - StreamReader tocStream; + CdrdaoDisc discimage; Stream imageStream; /// <summary>Dictionary, index is track #, value is TrackFile</summary> Dictionary<uint, ulong> offsetmap; List<Partition> partitions; - CdrdaoDisc discimage; - #endregion + StreamReader tocStream; - #region Parsing regexs - const string COMMENT_REGEX = "^\\s*\\/{2}(?<comment>.+)$"; - const string DISK_TYPE_REGEX = "^\\s*(?<type>(CD_DA|CD_ROM_XA|CD_ROM|CD_I))"; - const string MCN_REGEX = "^\\s*CATALOG\\s*\"(?<catalog>[\\d]{13,13})\""; - const string TRACK_REGEX = - "^\\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 COPY_REGEX = "^\\s*(?<no>NO)?\\s*COPY"; - const string EMPHASIS_REGEX = "^\\s*(?<no>NO)?\\s*PRE_EMPHASIS"; - const string STEREO_REGEX = "^\\s*(?<num>(TWO|FOUR))_CHANNEL_AUDIO"; - const string ISRC_REGEX = "^\\s*ISRC\\s*\"(?<isrc>[A-Z0-9]{5,5}[0-9]{7,7})\""; - const string INDEX_REGEX = "^\\s*INDEX\\s*(?<address>\\d+:\\d+:\\d+)"; - const string PREGAP_REGEX = "^\\s*START\\s*(?<address>\\d+:\\d+:\\d+)?"; - const string ZERO_PREGAP_REGEX = "^\\s*PREGAP\\s*(?<length>\\d+:\\d+:\\d+)"; - const string ZERO_DATA_REGEX = "^\\s*ZERO\\s*(?<length>\\d+:\\d+:\\d+)"; - const string ZERO_AUDIO_REGEX = "^\\s*SILENCE\\s*(?<length>\\d+:\\d+:\\d+)"; - const string AUDIO_FILE_REGEX = - "^\\s*(AUDIO)?FILE\\s*\"(?<filename>.+)\"\\s*(#(?<base_offset>\\d+))?\\s*((?<start>[\\d]+:[\\d]+:[\\d]+)|(?<start_num>\\d+))\\s*(?<length>[\\d]+:[\\d]+:[\\d]+)?" - ; - const string FILE_REGEX = - "^\\s*DATAFILE\\s*\"(?<filename>.+)\"\\s*(#(?<base_offset>\\d+))?\\s*(?<length>[\\d]+:[\\d]+:[\\d]+)?"; - - // CD-Text - const string TITLE_REGEX = "^\\s*TITLE\\s*\"(?<title>.+)\""; - const string PERFORMER_REGEX = "^\\s*PERFORMER\\s*\"(?<performer>.+)\""; - const string SONGWRITER_REGEX = "^\\s*SONGWRITER\\s*\"(?<songwriter>.+)\""; - const string COMPOSER_REGEX = "^\\s*COMPOSER\\s*\"(?<composer>.+)\""; - const string ARRANGER_REGEX = "^\\s*ARRANGER\\s*\"(?<arranger>.+)\""; - const string MESSAGE_REGEX = "^\\s*MESSAGE\\s*\"(?<message>.+)\""; - const string DISC_ID_REGEX = "^\\s*DISC_ID\\s*\"(?<discid>.+)\""; - const string UPC_REGEX = "^\\s*UPC_EAN\\s*\"(?<catalog>[\\d]{13,13})\""; - - // Unused - const string CD_TEXT_REGEX = "^\\s*CD_TEXT\\s*\\{"; - const string LANGUAGE_REGEX = "^\\s*LANGUAGE\\s*(?<code>\\d+)\\s*\\{"; - const string CLOSURE_REGEX = "^\\s*\\}"; - const string LANGUAGE_MAP_REGEX = "^\\s*LANGUAGE_MAP\\s*\\{"; - const string LANGUAGE_MAPPING_REGEX = "^\\s*(?<code>\\d+)\\s?\\:\\s?(?<language>\\d+|\\w+)"; - #endregion - - #region Public methods public Cdrdao() { Name = "CDRDAO tocfile"; @@ -242,7 +136,6 @@ namespace DiscImageChef.DiscImages DriveFirmwareRevision = null }; } - #endregion Public methods public override bool IdentifyImage(Filter imageFilter) { @@ -272,8 +165,8 @@ namespace DiscImageChef.DiscImages tocStream = new StreamReader(imageFilter.GetDataForkStream()); - Regex cr = new Regex(COMMENT_REGEX); - Regex dr = new Regex(DISK_TYPE_REGEX); + Regex cr = new Regex(REGEX_COMMENT); + Regex dr = new Regex(REGEX_DISCTYPE); while(tocStream.Peek() >= 0) { @@ -292,8 +185,7 @@ namespace DiscImageChef.DiscImages } catch(Exception ex) { - DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", - cdrdaoFilter.GetFilename()); + 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; @@ -313,34 +205,34 @@ namespace DiscImageChef.DiscImages bool intrack = false; // Initialize all RegExs - Regex regexComment = new Regex(COMMENT_REGEX); - Regex regexDiskType = new Regex(DISK_TYPE_REGEX); - Regex regexMcn = new Regex(MCN_REGEX); - Regex regexTrack = new Regex(TRACK_REGEX); - Regex regexCopy = new Regex(COPY_REGEX); - Regex regexEmphasis = new Regex(EMPHASIS_REGEX); - Regex regexStereo = new Regex(STEREO_REGEX); - Regex regexIsrc = new Regex(ISRC_REGEX); - Regex regexIndex = new Regex(INDEX_REGEX); - Regex regexPregap = new Regex(PREGAP_REGEX); - Regex regexZeroPregap = new Regex(ZERO_PREGAP_REGEX); - Regex regexZeroData = new Regex(ZERO_DATA_REGEX); - Regex regexZeroAudio = new Regex(ZERO_AUDIO_REGEX); - Regex regexAudioFile = new Regex(AUDIO_FILE_REGEX); - Regex regexFile = new Regex(FILE_REGEX); - Regex regexTitle = new Regex(TITLE_REGEX); - Regex regexPerformer = new Regex(PERFORMER_REGEX); - Regex regexSongwriter = new Regex(SONGWRITER_REGEX); - Regex regexComposer = new Regex(COMPOSER_REGEX); - Regex regexArranger = new Regex(ARRANGER_REGEX); - Regex regexMessage = new Regex(MESSAGE_REGEX); - Regex regexDiscId = new Regex(DISC_ID_REGEX); - Regex regexUpc = new Regex(UPC_REGEX); - Regex regexCdText = new Regex(CD_TEXT_REGEX); - Regex regexLanguage = new Regex(LANGUAGE_REGEX); - Regex regexClosure = new Regex(CLOSURE_REGEX); - Regex regexLanguageMap = new Regex(LANGUAGE_MAP_REGEX); - Regex regexLanguageMapping = new Regex(LANGUAGE_MAPPING_REGEX); + Regex regexComment = new Regex(REGEX_COMMENT); + Regex regexDiskType = new Regex(REGEX_DISCTYPE); + Regex regexMcn = new Regex(REGEX_MCN); + Regex regexTrack = new Regex(REGEX_TRACK); + Regex regexCopy = new Regex(REGEX_COPY); + Regex regexEmphasis = new Regex(REGEX_EMPHASIS); + Regex regexStereo = new Regex(REGEX_STEREO); + Regex regexIsrc = new Regex(REGEX_ISRC); + Regex regexIndex = new Regex(REGEX_INDEX); + Regex regexPregap = new Regex(REGEX_PREGAP); + Regex regexZeroPregap = new Regex(REGEX_ZERO_PREGAP); + Regex regexZeroData = new Regex(REGEX_ZERO_DATA); + Regex regexZeroAudio = new Regex(REGEX_ZERO_AUDIO); + Regex regexAudioFile = new Regex(REGEX_FILE_AUDIO); + Regex regexFile = new Regex(REGEX_FILE_DATA); + Regex regexTitle = new Regex(REGEX_TITLE); + Regex regexPerformer = new Regex(REGEX_PERFORMER); + Regex regexSongwriter = new Regex(REGEX_SONGWRITER); + Regex regexComposer = new Regex(REGEX_COMPOSER); + Regex regexArranger = new Regex(REGEX_ARRANGER); + Regex regexMessage = new Regex(REGEX_MESSAGE); + Regex regexDiscId = new Regex(REGEX_DISC_ID); + Regex regexUpc = new Regex(REGEX_UPC); + Regex regexCdText = new Regex(REGEX_CD_TEXT); + Regex regexLanguage = new Regex(REGEX_LANGUAGE); + Regex regexClosure = new Regex(REGEX_CLOSURE); + Regex regexLanguageMap = new Regex(REGEX_LANGUAGE_MAP); + Regex regexLanguageMapping = new Regex(REGEX_LANGUAGE_MAPPING); // Initialize all RegEx matches Match matchComment; @@ -464,8 +356,8 @@ namespace DiscImageChef.DiscImages { if(matchTrack.Groups["subchan"].Value == "") DicConsole.DebugWriteLine("CDRDAO plugin", - "Found TRACK type \"{1}\" with no subchannel at line {0}", lineNumber, - matchTrack.Groups["type"].Value); + "Found TRACK type \"{1}\" with no subchannel at line {0}", + lineNumber, matchTrack.Groups["type"].Value); else DicConsole.DebugWriteLine("CDRDAO plugin", "Found TRACK type \"{1}\" subchannel {2} at line {0}", lineNumber, @@ -503,7 +395,8 @@ namespace DiscImageChef.DiscImages currenttrack.Bps = 2336; break; default: - throw new NotSupportedException($"Track mode {matchTrack.Groups["type"].Value} is unsupported"); + throw new + NotSupportedException($"Track mode {matchTrack.Groups["type"].Value} is unsupported"); } switch(matchTrack.Groups["subchan"].Value) @@ -595,8 +488,8 @@ namespace DiscImageChef.DiscImages FiltersList filtersList; if(matchAudioFile.Success) { - DicConsole.DebugWriteLine("CDRDAO plugin", "Found AUDIOFILE \"{1}\" at line {0}", lineNumber, - matchAudioFile.Groups["filename"].Value); + DicConsole.DebugWriteLine("CDRDAO plugin", "Found AUDIOFILE \"{1}\" at line {0}", + lineNumber, matchAudioFile.Groups["filename"].Value); filtersList = new FiltersList(); currenttrack.Trackfile = new CdrdaoTrackFile @@ -617,8 +510,8 @@ namespace DiscImageChef.DiscImages if(matchAudioFile.Groups["start"].Value != "") { string[] startString = matchAudioFile.Groups["start"].Value.Split(':'); - startSectors = ulong.Parse(startString[0]) * 60 * 75 + ulong.Parse(startString[1]) * 75 + - ulong.Parse(startString[2]); + startSectors = ulong.Parse(startString[0]) * 60 * 75 + + ulong.Parse(startString[1]) * 75 + ulong.Parse(startString[2]); } currenttrack.Trackfile.Offset += startSectors * currenttrack.Bps; @@ -673,15 +566,15 @@ namespace DiscImageChef.DiscImages } else if(matchPerformer.Success) { - DicConsole.DebugWriteLine("CDRDAO plugin", "Found PERFORMER \"{1}\" at line {0}", lineNumber, - matchPerformer.Groups["performer"].Value); + DicConsole.DebugWriteLine("CDRDAO plugin", "Found PERFORMER \"{1}\" at line {0}", + lineNumber, matchPerformer.Groups["performer"].Value); if(intrack) currenttrack.Performer = matchPerformer.Groups["performer"].Value; else discimage.Performer = matchPerformer.Groups["performer"].Value; } else if(matchSongwriter.Success) { - DicConsole.DebugWriteLine("CDRDAO plugin", "Found SONGWRITER \"{1}\" at line {0}", lineNumber, - matchSongwriter.Groups["songwriter"].Value); + DicConsole.DebugWriteLine("CDRDAO plugin", "Found SONGWRITER \"{1}\" at line {0}", + lineNumber, matchSongwriter.Groups["songwriter"].Value); if(intrack) currenttrack.Songwriter = matchSongwriter.Groups["songwriter"].Value; else discimage.Songwriter = matchSongwriter.Groups["songwriter"].Value; } @@ -1041,14 +934,26 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrdaoTrack in discimage.Tracks where cdrdaoTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrdaoTrack.Sectors select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrdaoTrack in discimage.Tracks + where cdrdaoTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrdaoTrack.Sectors + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrdaoTrack in discimage.Tracks where cdrdaoTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrdaoTrack.Sectors select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrdaoTrack in discimage.Tracks + where cdrdaoTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrdaoTrack.Sectors + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -1057,7 +962,8 @@ namespace DiscImageChef.DiscImages { CdrdaoTrack dicTrack = new CdrdaoTrack {Sequence = 0}; - foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) { + foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) + { dicTrack = cdrdaoTrack; break; } @@ -1148,7 +1054,8 @@ namespace DiscImageChef.DiscImages { CdrdaoTrack dicTrack = new CdrdaoTrack {Sequence = 0}; - foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) { + foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) + { dicTrack = cdrdaoTrack; break; } @@ -1321,7 +1228,13 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrdaoTrack in discimage.Tracks where cdrdaoTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrdaoTrack.Sectors select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrdaoTrack in discimage.Tracks + where cdrdaoTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrdaoTrack.Sectors + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -1330,7 +1243,8 @@ namespace DiscImageChef.DiscImages { CdrdaoTrack dicTrack = new CdrdaoTrack {Sequence = 0}; - foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) { + foreach(CdrdaoTrack cdrdaoTrack in discimage.Tracks.Where(cdrdaoTrack => cdrdaoTrack.Sequence == track)) + { dicTrack = cdrdaoTrack; break; } @@ -1492,8 +1406,8 @@ namespace DiscImageChef.DiscImages if(cdrTrack.Subchannel) { dicTrack.TrackSubchannelType = cdrTrack.Packedsubchannel - ? TrackSubchannelType.PackedInterleaved - : TrackSubchannelType.RawInterleaved; + ? TrackSubchannelType.PackedInterleaved + : TrackSubchannelType.RawInterleaved; dicTrack.TrackSubchannelFilter = cdrTrack.Trackfile.Datafilter; dicTrack.TrackSubchannelFile = cdrTrack.Trackfile.Datafilter.GetFilename(); dicTrack.TrackSubchannelOffset = cdrTrack.Trackfile.Offset; @@ -1595,15 +1509,12 @@ namespace DiscImageChef.DiscImages return null; } - #region Not implemented methods public override List<Session> GetSessions() { // TODO throw new NotImplementedException(); } - #endregion - #region Private methods static ushort CdrdaoTrackTypeToBytesPerSector(string trackType) { switch(trackType) @@ -1651,9 +1562,7 @@ namespace DiscImageChef.DiscImages default: return TrackType.Data; } } - #endregion - #region Unsupported features public override int GetMediaSequence() { return ImageInfo.MediaSequence; @@ -1703,6 +1612,102 @@ namespace DiscImageChef.DiscImages { return ImageInfo.ImageCreator; } - #endregion + + [SuppressMessage("ReSharper", "NotAccessedField.Local")] + struct CdrdaoTrackFile + { + /// <summary>Track #</summary> + public uint Sequence; + /// <summary>Filter of file containing track</summary> + public Filter 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 } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CDRWin.cs b/DiscImageChef.DiscImages/CDRWin.cs index 73c9bec74..ae8fae3a6 100644 --- a/DiscImageChef.DiscImages/CDRWin.cs +++ b/DiscImageChef.DiscImages/CDRWin.cs @@ -46,99 +46,6 @@ namespace DiscImageChef.DiscImages // TODO: Implement track flags public class CdrWin : ImagePlugin { - #region Internal structures - struct CdrWinTrackFile - { - /// <summary>Track #</summary> - public uint Sequence; - /// <summary>Filter of file containing track</summary> - public Filter 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; - } - #endregion - - 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; - } - - #region Internal consts // Type for FILE entity /// <summary>Data as-is in little-endian</summary> const string CDRWIN_DISK_TYPE_LITTLE_ENDIAN = "BINARY"; @@ -238,45 +145,39 @@ namespace DiscImageChef.DiscImages const string CDRWIN_DISK_TYPE_BDRDL = "BD-R DL"; /// <summary>DiskType.BDRE</summary> const string CDRWIN_DISK_TYPE_BDREDL = "BD-RE DL"; - #endregion - #region Internal variables + 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 = "\\bCATALOG\\s+(?<catalog>\\d{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*)+$"; + Filter cdrwinFilter; StreamReader cueStream; + CdrWinDisc discimage; Stream imageStream; /// <summary>Dictionary, index is track #, value is TrackFile</summary> Dictionary<uint, ulong> offsetmap; - CdrWinDisc discimage; List<Partition> partitions; - #endregion - #region Parsing regexs - const string SESSION_REGEX = "\\bREM\\s+SESSION\\s+(?<number>\\d+).*$"; - const string DISK_TYPE_REGEX = "\\bREM\\s+ORIGINAL MEDIA-TYPE:\\s+(?<mediatype>.+)$"; - const string LEAD_OUT_REGEX = "\\bREM\\s+LEAD-OUT\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - // Not checked - const string LBA_REGEX = "\\bREM MSF:\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)\\s+=\\s+LBA:\\s+(?<lba>[\\d]+)$"; - const string DISK_ID_REGEX = "\\bDISC_ID\\s+(?<diskid>[\\da-f]{8})$"; - const string BAR_CODE_REGEX = "\\bUPC_EAN\\s+(?<barcode>[\\d]{12,13})$"; - const string COMMENT_REGEX = "\\bREM\\s+(?<comment>.+)$"; - const string CD_TEXT_REGEX = "\\bCDTEXTFILE\\s+(?<filename>.+)$"; - const string MCN_REGEX = "\\bCATALOG\\s+(?<catalog>\\d{13})$"; - const string TITLE_REGEX = "\\bTITLE\\s+(?<title>.+)$"; - const string GENRE_REGEX = "\\bGENRE\\s+(?<genre>.+)$"; - const string ARRANGER_REGEX = "\\bARRANGER\\s+(?<arranger>.+)$"; - const string COMPOSER_REGEX = "\\bCOMPOSER\\s+(?<composer>.+)$"; - const string PERFORMER_REGEX = "\\bPERFORMER\\s+(?<performer>.+)$"; - const string SONG_WRITER_REGEX = "\\bSONGWRITER\\s+(?<songwriter>.+)$"; - const string FILE_REGEX = "\\bFILE\\s+(?<filename>.+)\\s+(?<type>\\S+)$"; - const string TRACK_REGEX = "\\bTRACK\\s+(?<number>\\d+)\\s+(?<type>\\S+)$"; - const string ISRC_REGEX = "\\bISRC\\s+(?<isrc>\\w{12})$"; - const string INDEX_REGEX = "\\bINDEX\\s+(?<index>\\d+)\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - const string PREGAP_REGEX = "\\bPREGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - const string POSTGAP_REGEX = "\\bPOSTGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - const string FLAGS_REGEX = "\\bFLAGS\\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\\s*)+$"; - #endregion - - #region Methods public CdrWin() { Name = "CDRWin cuesheet"; @@ -338,11 +239,11 @@ namespace DiscImageChef.DiscImages { string line = cueStream.ReadLine(); - Regex sr = new Regex(SESSION_REGEX); - Regex rr = new Regex(COMMENT_REGEX); - Regex cr = new Regex(MCN_REGEX); - Regex fr = new Regex(FILE_REGEX); - Regex tr = new Regex(CD_TEXT_REGEX); + 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()); @@ -380,28 +281,28 @@ namespace DiscImageChef.DiscImages byte currentsession = 1; // Initialize all RegExs - Regex regexSession = new Regex(SESSION_REGEX); - Regex regexDiskType = new Regex(DISK_TYPE_REGEX); - Regex regexLeadOut = new Regex(LEAD_OUT_REGEX); - Regex regexLba = new Regex(LBA_REGEX); - Regex regexDiskId = new Regex(DISK_ID_REGEX); - Regex regexBarCode = new Regex(BAR_CODE_REGEX); - Regex regexComment = new Regex(COMMENT_REGEX); - Regex regexCdText = new Regex(CD_TEXT_REGEX); - Regex regexMcn = new Regex(MCN_REGEX); - Regex regexTitle = new Regex(TITLE_REGEX); - Regex regexGenre = new Regex(GENRE_REGEX); - Regex regexArranger = new Regex(ARRANGER_REGEX); - Regex regexComposer = new Regex(COMPOSER_REGEX); - Regex regexPerformer = new Regex(PERFORMER_REGEX); - Regex regexSongWriter = new Regex(SONG_WRITER_REGEX); - Regex regexFile = new Regex(FILE_REGEX); - Regex regexTrack = new Regex(TRACK_REGEX); - Regex regexIsrc = new Regex(ISRC_REGEX); - Regex regexIndex = new Regex(INDEX_REGEX); - Regex regexPregap = new Regex(PREGAP_REGEX); - Regex regexPostgap = new Regex(POSTGAP_REGEX); - Regex regexFlags = new Regex(FLAGS_REGEX); + Regex regexSession = new Regex(REGEX_SESSION); + Regex regexDiskType = new Regex(REGEX_MEDIA_TYPE); + Regex regexLeadOut = new Regex(REGEX_LEAD_OUT); + Regex regexLba = new Regex(REGEX_LBA); + Regex regexDiskId = new Regex(REGEX_DISC_ID); + Regex regexBarCode = new Regex(REGEX_BARCODE); + Regex regexComment = new Regex(REGEX_COMMENT); + Regex regexCdText = new Regex(REGEX_CDTEXT); + Regex regexMcn = new Regex(REGEX_MCN); + Regex regexTitle = new Regex(REGEX_TITLE); + Regex regexGenre = new Regex(REGEX_GENRE); + Regex regexArranger = new Regex(REGEX_ARRANGER); + Regex regexComposer = new Regex(REGEX_COMPOSER); + Regex regexPerformer = new Regex(REGEX_PERFORMER); + Regex regexSongWriter = new Regex(REGEX_SONGWRITER); + Regex regexFile = new Regex(REGEX_FILE); + Regex regexTrack = new Regex(REGEX_TRACK); + Regex regexIsrc = new Regex(REGEX_ISRC); + Regex regexIndex = new Regex(REGEX_INDEX); + Regex regexPregap = new Regex(REGEX_PREGAP); + Regex regexPostgap = new Regex(REGEX_POSTGAP); + Regex regexFlags = new Regex(REGEX_FLAGS); // Initialize all RegEx matches Match matchTrack; @@ -459,7 +360,8 @@ namespace DiscImageChef.DiscImages if(matchDiskType.Success && !intrack) { - DicConsole.DebugWriteLine("CDRWin plugin", "Found REM ORIGINAL MEDIA TYPE at line {0}", lineNumber); + DicConsole.DebugWriteLine("CDRWin plugin", "Found REM ORIGINAL MEDIA TYPE at line {0}", + lineNumber); discimage.Disktypestr = matchDiskType.Groups[1].Value; } else if(matchDiskType.Success && intrack) @@ -472,8 +374,10 @@ namespace DiscImageChef.DiscImages // What happens between sessions } - else if(matchLba.Success) DicConsole.DebugWriteLine("CDRWin plugin", "Found REM MSF at line {0}", lineNumber); - else if(matchLeadOut.Success) DicConsole.DebugWriteLine("CDRWin plugin", "Found REM LEAD-OUT at line {0}", lineNumber); + else if(matchLba.Success) + DicConsole.DebugWriteLine("CDRWin plugin", "Found REM MSF at line {0}", lineNumber); + else if(matchLeadOut.Success) + DicConsole.DebugWriteLine("CDRWin plugin", "Found REM LEAD-OUT at line {0}", lineNumber); else if(matchComment.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM at line {0}", lineNumber); @@ -561,14 +465,14 @@ namespace DiscImageChef.DiscImages currentfile.Filetype = matchFile.Groups[2].Value; // Check if file path is quoted - if(datafile[0] == '"' && datafile[datafile.Length - 1] == '"') datafile = datafile.Substring(1, datafile.Length - 2); // Unquote it + if(datafile[0] == '"' && datafile[datafile.Length - 1] == '"') + datafile = datafile.Substring(1, datafile.Length - 2); // Unquote it currentfile.Datafilter = filtersList.GetFilter(datafile); // Check if file exists if(currentfile.Datafilter == null) - if(datafile[0] == '/' || datafile[0] == '/' && datafile[1] == '.' - ) // UNIX absolute path + if(datafile[0] == '/' || datafile[0] == '/' && datafile[1] == '.') // UNIX absolute path { Regex unixpath = new Regex("^(.+)/([^/]+)$"); Match unixpathmatch = unixpath.Match(datafile); @@ -643,7 +547,8 @@ namespace DiscImageChef.DiscImages throw new FeatureSupportedButNotImplementedImageException($"Unsupported file type {currentfile.Filetype}"); default: - throw new FeatureUnsupportedImageException($"Unknown file type {currentfile.Filetype}"); + throw new + FeatureUnsupportedImageException($"Unknown file type {currentfile.Filetype}"); } currentfile.Offset = 0; @@ -671,8 +576,7 @@ namespace DiscImageChef.DiscImages { DicConsole.DebugWriteLine("CDRWin plugin", "Found INDEX at line {0}", lineNumber); if(!intrack) - throw new - FeatureUnsupportedImageException($"Found INDEX before a track {lineNumber}"); + throw new FeatureUnsupportedImageException($"Found INDEX before a track {lineNumber}"); int index = int.Parse(matchIndex.Groups[1].Value); ulong offset = CdrWinMsftoLba(matchIndex.Groups[2].Value); @@ -702,8 +606,7 @@ namespace DiscImageChef.DiscImages if((index == 0 || index == 1 && !currenttrack.Indexes.ContainsKey(0)) && currenttrack.Sequence == 1) { - DicConsole.DebugWriteLine("CDRWin plugin", - "Sets currentfile.offset to {0} at line 559", + DicConsole.DebugWriteLine("CDRWin plugin", "Sets currentfile.offset to {0} at line 559", offset * currenttrack.Bps); currentfile.Offset = offset * currenttrack.Bps; } @@ -715,8 +618,7 @@ namespace DiscImageChef.DiscImages { DicConsole.DebugWriteLine("CDRWin plugin", "Found ISRC at line {0}", lineNumber); if(!intrack) - throw new - FeatureUnsupportedImageException($"Found ISRC before a track {lineNumber}"); + throw new FeatureUnsupportedImageException($"Found ISRC before a track {lineNumber}"); currenttrack.Isrc = matchIsrc.Groups[1].Value; } @@ -771,7 +673,8 @@ namespace DiscImageChef.DiscImages if(intrack) { - if(currenttrack.Indexes.ContainsKey(0) && currenttrack.Pregap == 0) currenttrack.Indexes.TryGetValue(0, out currenttrack.Pregap); + if(currenttrack.Indexes.ContainsKey(0) && currenttrack.Pregap == 0) + currenttrack.Indexes.TryGetValue(0, out currenttrack.Pregap); currentfile.Sequence = currenttrack.Sequence; currenttrack.Trackfile = currentfile; cuetracks[currenttrack.Sequence - 1] = currenttrack; @@ -1297,14 +1200,26 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrwinTrack in discimage.Tracks where cdrwinTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrwinTrack.Sectors select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrwinTrack in discimage.Tracks + where cdrwinTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrwinTrack.Sectors + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrwinTrack in discimage.Tracks where cdrwinTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrwinTrack.Sectors select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrwinTrack in discimage.Tracks + where cdrwinTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrwinTrack.Sectors + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -1313,7 +1228,8 @@ namespace DiscImageChef.DiscImages { CdrWinTrack dicTrack = new CdrWinTrack {Sequence = 0}; - foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) { + foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) + { dicTrack = cdrwinTrack; break; } @@ -1416,7 +1332,8 @@ namespace DiscImageChef.DiscImages { CdrWinTrack dicTrack = new CdrWinTrack {Sequence = 0}; - foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) { + foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) + { dicTrack = cdrwinTrack; break; } @@ -1604,7 +1521,13 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from cdrwinTrack in discimage.Tracks where cdrwinTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < cdrwinTrack.Sectors select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from cdrwinTrack in discimage.Tracks + where cdrwinTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < cdrwinTrack.Sectors + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -1613,7 +1536,8 @@ namespace DiscImageChef.DiscImages { CdrWinTrack dicTrack = new CdrWinTrack {Sequence = 0}; - foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) { + foreach(CdrWinTrack cdrwinTrack in discimage.Tracks.Where(cdrwinTrack => cdrwinTrack.Sequence == track)) + { dicTrack = cdrwinTrack; break; } @@ -1887,9 +1811,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, @@ -1918,18 +1841,15 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion - #region Private methods static ulong CdrWinMsftoLba(string msf) { ulong minute, second, frame, sectors; @@ -2037,9 +1957,7 @@ namespace DiscImageChef.DiscImages default: return MediaType.Unknown; } } - #endregion - #region Unsupported features public override int GetMediaSequence() { return ImageInfo.MediaSequence; @@ -2089,6 +2007,95 @@ namespace DiscImageChef.DiscImages { return ImageInfo.ImageCreator; } - #endregion + + struct CdrWinTrackFile + { + /// <summary>Track #</summary> + public uint Sequence; + /// <summary>Filter of file containing track</summary> + public Filter 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; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CHD.cs b/DiscImageChef.DiscImages/CHD.cs index d2d34f450..efca3b61f 100644 --- a/DiscImageChef.DiscImages/CHD.cs +++ b/DiscImageChef.DiscImages/CHD.cs @@ -50,445 +50,6 @@ namespace DiscImageChef.DiscImages // TODO: Implement PCMCIA support public class Chd : ImagePlugin { - #region Internal Structures - 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 - } - - // Hunks are represented in a 64 bit integer with 44 bit as offset, 20 bits as length - // Sectors are fixed at 512 bytes/sector - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdHeaderV1 - { - /// <summary> - /// Magic identifier, 'MComprHD' - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; - /// <summary> - /// Length of header - /// </summary> - public uint length; - /// <summary> - /// Image format version - /// </summary> - public uint version; - /// <summary> - /// Image flags, <see cref="ChdFlags"/> - /// </summary> - public uint flags; - /// <summary> - /// Compression algorithm, <see cref="ChdCompression"/> - /// </summary> - public uint compression; - /// <summary> - /// Sectors per hunk - /// </summary> - public uint hunksize; - /// <summary> - /// Total # of hunk in image - /// </summary> - public uint totalhunks; - /// <summary> - /// Cylinders on disk - /// </summary> - public uint cylinders; - /// <summary> - /// Heads per cylinder - /// </summary> - public uint heads; - /// <summary> - /// Sectors per track - /// </summary> - public uint sectors; - /// <summary> - /// MD5 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; - /// <summary> - /// MD5 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; - } - - // Hunks are represented in a 64 bit integer with 44 bit as offset, 20 bits as length - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdHeaderV2 - { - /// <summary> - /// Magic identifier, 'MComprHD' - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; - /// <summary> - /// Length of header - /// </summary> - public uint length; - /// <summary> - /// Image format version - /// </summary> - public uint version; - /// <summary> - /// Image flags, <see cref="ChdFlags"/> - /// </summary> - public uint flags; - /// <summary> - /// Compression algorithm, <see cref="ChdCompression"/> - /// </summary> - public uint compression; - /// <summary> - /// Sectors per hunk - /// </summary> - public uint hunksize; - /// <summary> - /// Total # of hunk in image - /// </summary> - public uint totalhunks; - /// <summary> - /// Cylinders on disk - /// </summary> - public uint cylinders; - /// <summary> - /// Heads per cylinder - /// </summary> - public uint heads; - /// <summary> - /// Sectors per track - /// </summary> - public uint sectors; - /// <summary> - /// MD5 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; - /// <summary> - /// MD5 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; - /// <summary> - /// Bytes per sector - /// </summary> - public uint seclen; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdHeaderV3 - { - /// <summary> - /// Magic identifier, 'MComprHD' - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; - /// <summary> - /// Length of header - /// </summary> - public uint length; - /// <summary> - /// Image format version - /// </summary> - public uint version; - /// <summary> - /// Image flags, <see cref="ChdFlags"/> - /// </summary> - public uint flags; - /// <summary> - /// Compression algorithm, <see cref="ChdCompression"/> - /// </summary> - public uint compression; - /// <summary> - /// Total # of hunk in image - /// </summary> - public uint totalhunks; - /// <summary> - /// Total bytes in image - /// </summary> - public ulong logicalbytes; - /// <summary> - /// Offset to first metadata blob - /// </summary> - public ulong metaoffset; - /// <summary> - /// MD5 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; - /// <summary> - /// MD5 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; - /// <summary> - /// Bytes per hunk - /// </summary> - public uint hunkbytes; - /// <summary> - /// SHA1 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; - /// <summary> - /// SHA1 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdMapV3Entry - { - /// <summary> - /// Offset to hunk from start of image - /// </summary> - public ulong offset; - /// <summary> - /// CRC32 of uncompressed hunk - /// </summary> - public uint crc; - /// <summary> - /// Lower 16 bits of length - /// </summary> - public ushort lengthLsb; - /// <summary> - /// Upper 8 bits of length - /// </summary> - public byte length; - /// <summary> - /// Hunk flags - /// </summary> - public byte flags; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdTrackOld - { - public uint type; - public uint subType; - public uint dataSize; - public uint subSize; - public uint frames; - public uint extraFrames; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdHeaderV4 - { - /// <summary> - /// Magic identifier, 'MComprHD' - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; - /// <summary> - /// Length of header - /// </summary> - public uint length; - /// <summary> - /// Image format version - /// </summary> - public uint version; - /// <summary> - /// Image flags, <see cref="ChdFlags"/> - /// </summary> - public uint flags; - /// <summary> - /// Compression algorithm, <see cref="ChdCompression"/> - /// </summary> - public uint compression; - /// <summary> - /// Total # of hunk in image - /// </summary> - public uint totalhunks; - /// <summary> - /// Total bytes in image - /// </summary> - public ulong logicalbytes; - /// <summary> - /// Offset to first metadata blob - /// </summary> - public ulong metaoffset; - /// <summary> - /// Bytes per hunk - /// </summary> - public uint hunkbytes; - /// <summary> - /// SHA1 of raw+meta data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; - /// <summary> - /// SHA1 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; - /// <summary> - /// SHA1 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] rawsha1; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdHeaderV5 - { - /// <summary> - /// Magic identifier, 'MComprHD' - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; - /// <summary> - /// Length of header - /// </summary> - public uint length; - /// <summary> - /// Image format version - /// </summary> - public uint version; - /// <summary> - /// Compressor 0 - /// </summary> - public uint compressor0; - /// <summary> - /// Compressor 1 - /// </summary> - public uint compressor1; - /// <summary> - /// Compressor 2 - /// </summary> - public uint compressor2; - /// <summary> - /// Compressor 3 - /// </summary> - public uint compressor3; - /// <summary> - /// Total bytes in image - /// </summary> - public ulong logicalbytes; - /// <summary> - /// Offset to hunk map - /// </summary> - public ulong mapoffset; - /// <summary> - /// Offset to first metadata blob - /// </summary> - public ulong metaoffset; - /// <summary> - /// Bytes per hunk - /// </summary> - public uint hunkbytes; - /// <summary> - /// Bytes per unit within hunk - /// </summary> - public uint unitbytes; - /// <summary> - /// SHA1 of raw data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] rawsha1; - /// <summary> - /// SHA1 of raw+meta data - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; - /// <summary> - /// SHA1 of parent file - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdCompressedMapHeaderV5 - { - /// <summary> - /// Length of compressed map - /// </summary> - public uint length; - /// <summary> - /// Offset of first block (48 bits) and CRC16 of map (16 bits) - /// </summary> - public ulong startAndCrc; - /// <summary> - /// Bits used to encode compressed length on map entry - /// </summary> - public byte bitsUsedToEncodeCompLength; - /// <summary> - /// Bits used to encode self-refs - /// </summary> - public byte bitsUsedToEncodeSelfRefs; - /// <summary> - /// Bits used to encode parent unit refs - /// </summary> - public byte bitsUsedToEncodeParentUnits; - public byte reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdMapV5Entry - { - /// <summary> - /// Compression (8 bits) and length (24 bits) - /// </summary> - public uint compAndLength; - /// <summary> - /// Offset (48 bits) and CRC (16 bits) - /// </summary> - public ulong offsetAndCrc; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChdMetadataHeader - { - public uint tag; - public uint flagsAndLength; - public ulong next; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct HunkSector - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public ulong[] hunkEntry; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct HunkSectorSmall - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public uint[] hunkEntry; - } - #endregion - - #region Internal Constants - /// <summary>"MComprHD"</summary> - readonly byte[] chdTag = {0x4D, 0x43, 0x6F, 0x6D, 0x70, 0x72, 0x48, 0x44}; /// <summary>"GDDD"</summary> const uint HARD_DISK_METADATA = 0x47444444; /// <summary>"IDNT"</summary> @@ -512,14 +73,14 @@ namespace DiscImageChef.DiscImages /// <summary>"AVLD"</summary> const uint AV_LASER_DISC_METADATA = 0x41564C44; - const string HARD_DISK_METADATA_REGEX = + const string REGEX_METADATA_HDD = "CYLS:(?<cylinders>\\d+),HEADS:(?<heads>\\d+),SECS:(?<sectors>\\d+),BPS:(?<bps>\\d+)"; - const string CDROM_METADATA_REGEX = + const string REGEX_METADATA_CDROM = "TRACK:(?<track>\\d+) TYPE:(?<track_type>\\S+) SUBTYPE:(?<sub_type>\\S+) FRAMES:(?<frames>\\d+)"; - const string CDROM_METADATA2_REGEX = + 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 GDROM_METADATA_REGEX = + 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+)" ; @@ -541,41 +102,37 @@ namespace DiscImageChef.DiscImages const string SUB_TYPE_COOKED = "RW"; const string SUB_TYPE_RAW = "RW_RAW"; const string SUB_TYPE_NONE = "NONE"; - #endregion - #region Internal variables - ulong[] hunkTable; - uint[] hunkTableSmall; + const int MAX_CACHE_SIZE = 16777216; + + /// <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; - Stream imageStream; - uint sectorsPerHunk; + Dictionary<ulong, byte[]> hunkCache; byte[] hunkMap; - uint mapVersion; - uint bytesPerHunk; - uint totalHunks; - byte[] expectedChecksum; + ulong[] hunkTable; + uint[] hunkTableSmall; + byte[] identify; + Stream imageStream; bool isCdrom; - bool isHdd; bool isGdrom; - bool swapAudio; - - const int MAX_CACHE_SIZE = 16777216; + bool isHdd; + uint mapVersion; int maxBlockCache; int maxSectorCache; - - Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> hunkCache; - - Dictionary<uint, Track> tracks; - List<Partition> partitions; Dictionary<ulong, uint> offsetmap; - - byte[] identify; - byte[] cis; - #endregion + List<Partition> partitions; + Dictionary<ulong, byte[]> sectorCache; + uint sectorsPerHunk; + bool swapAudio; + uint totalHunks; + Dictionary<uint, Track> tracks; public Chd() { @@ -673,15 +230,15 @@ namespace DiscImageChef.DiscImages // This does the big-endian trick but reverses the order of elements also Array.Reverse(hunkSectorBytes); GCHandle handle = GCHandle.Alloc(hunkSectorBytes, GCHandleType.Pinned); - HunkSector hunkSector = (HunkSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HunkSector)); + HunkSector hunkSector = + (HunkSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HunkSector)); handle.Free(); // This restores the order of elements Array.Reverse(hunkSector.hunkEntry); if(hunkTable.Length >= i * 512 / 8 + 512 / 8) Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, 512 / 8); else - Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, - hunkTable.Length - i * 512 / 8); + Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, hunkTable.Length - i * 512 / 8); } DateTime end = DateTime.UtcNow; @@ -744,15 +301,15 @@ namespace DiscImageChef.DiscImages // This does the big-endian trick but reverses the order of elements also Array.Reverse(hunkSectorBytes); GCHandle handle = GCHandle.Alloc(hunkSectorBytes, GCHandleType.Pinned); - HunkSector hunkSector = (HunkSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HunkSector)); + HunkSector hunkSector = + (HunkSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HunkSector)); handle.Free(); // This restores the order of elements Array.Reverse(hunkSector.hunkEntry); if(hunkTable.Length >= i * 512 / 8 + 512 / 8) Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, 512 / 8); else - Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, - hunkTable.Length - i * 512 / 8); + Array.Copy(hunkSector.hunkEntry, 0, hunkTable, i * 512 / 8, hunkTable.Length - i * 512 / 8); } DateTime end = DateTime.UtcNow; @@ -921,8 +478,9 @@ namespace DiscImageChef.DiscImages // This does the big-endian trick but reverses the order of elements also Array.Reverse(hunkSectorBytes); GCHandle handle = GCHandle.Alloc(hunkSectorBytes, GCHandleType.Pinned); - HunkSectorSmall hunkSector = (HunkSectorSmall)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), - typeof(HunkSectorSmall)); + HunkSectorSmall hunkSector = + (HunkSectorSmall)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), + typeof(HunkSectorSmall)); handle.Free(); // This restores the order of elements Array.Reverse(hunkSector.hunkEntry); @@ -990,7 +548,7 @@ namespace DiscImageChef.DiscImages ImageNotSupportedException("Image cannot be a hard disk and a C/GD-ROM at the same time, aborting."); string gddd = StringHandlers.CToString(meta); - Regex gdddRegEx = new Regex(HARD_DISK_METADATA_REGEX); + Regex gdddRegEx = new Regex(REGEX_METADATA_HDD); Match gdddMatch = gdddRegEx.Match(gddd); if(gdddMatch.Success) { @@ -1125,7 +683,7 @@ namespace DiscImageChef.DiscImages ImageNotSupportedException("Image cannot be a GD-ROM and a CD-ROM at the same time, aborting."); string chtr = StringHandlers.CToString(meta); - Regex chtrRegEx = new Regex(CDROM_METADATA_REGEX); + Regex chtrRegEx = new Regex(REGEX_METADATA_CDROM); Match chtrMatch = chtrRegEx.Match(chtr); if(chtrMatch.Success) { @@ -1204,8 +762,7 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSubchannelFilter = imageFilter; break; default: - throw new - ImageNotSupportedException($"Unsupported subchannel type {subtype}"); + throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}"); } dicTrack.Indexes = new Dictionary<int, ulong>(); @@ -1234,7 +791,7 @@ namespace DiscImageChef.DiscImages ImageNotSupportedException("Image cannot be a GD-ROM and a CD-ROM at the same time, aborting."); string cht2 = StringHandlers.CToString(meta); - Regex cht2RegEx = new Regex(CDROM_METADATA2_REGEX); + Regex cht2RegEx = new Regex(REGEX_METADATA_CDROM2); Match cht2Match = cht2RegEx.Match(cht2); if(cht2Match.Success) { @@ -1318,8 +875,7 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSubchannelFilter = imageFilter; break; default: - throw new - ImageNotSupportedException($"Unsupported subchannel type {subtype}"); + throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}"); } dicTrack.Indexes = new Dictionary<int, ulong>(); @@ -1352,7 +908,7 @@ namespace DiscImageChef.DiscImages ImageNotSupportedException("Image cannot be a CD-ROM and a GD-ROM at the same time, aborting."); string chgd = StringHandlers.CToString(meta); - Regex chgdRegEx = new Regex(GDROM_METADATA_REGEX); + Regex chgdRegEx = new Regex(REGEX_METADATA_GDROM); Match chgdMatch = chgdRegEx.Match(chgd); if(chgdMatch.Success) { @@ -1437,8 +993,7 @@ namespace DiscImageChef.DiscImages dicTrack.TrackSubchannelFilter = imageFilter; break; default: - throw new - ImageNotSupportedException($"Unsupported subchannel type {subtype}"); + throw new ImageNotSupportedException($"Unsupported subchannel type {subtype}"); } dicTrack.Indexes = new Dictionary<int, ulong>(); @@ -1624,7 +1179,8 @@ namespace DiscImageChef.DiscImages Track GetTrack(ulong sector) { Track track = new Track(); - foreach(KeyValuePair<ulong, uint> kvp in offsetmap.Where(kvp => sector >= kvp.Key)) tracks.TryGetValue(kvp.Value, out track); + foreach(KeyValuePair<ulong, uint> kvp in offsetmap.Where(kvp => sector >= kvp.Key)) + tracks.TryGetValue(kvp.Value, out track); return track; } @@ -1651,7 +1207,8 @@ namespace DiscImageChef.DiscImages if(length == sectorsPerHunk * ImageInfo.SectorSize) hunk = compHunk; else if((ChdCompression)hdrCompression > ChdCompression.Zlib) - throw new ImageNotSupportedException($"Unsupported compression {(ChdCompression)hdrCompression}"); + throw new + ImageNotSupportedException($"Unsupported compression {(ChdCompression)hdrCompression}"); else { DeflateStream zStream = @@ -1739,8 +1296,7 @@ namespace DiscImageChef.DiscImages else throw new ImageNotSupportedException("Compressed v5 hunks not yet supported"); break; - default: - throw new ImageNotSupportedException($"Unsupported hunk map version {mapVersion}"); + default: throw new ImageNotSupportedException($"Unsupported hunk map version {mapVersion}"); } if(hunkCache.Count >= maxBlockCache) hunkCache.Clear(); @@ -1794,9 +1350,7 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, @@ -1827,9 +1381,7 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() @@ -1991,7 +1543,6 @@ namespace DiscImageChef.DiscImages if(!sectorCache.TryGetValue(sectorAddress, out byte[] sector)) { - track = GetTrack(sectorAddress); sectorSize = (uint)track.TrackRawBytesPerSector; @@ -2013,8 +1564,10 @@ namespace DiscImageChef.DiscImages uint sectorOffset; if(tag == SectorTagType.CdSectorSubchannel) - switch(track.TrackSubchannelType) { - case TrackSubchannelType.None: throw new FeatureNotPresentImageException("Requested sector does not contain subchannel"); + switch(track.TrackSubchannelType) + { + case TrackSubchannelType.None: + throw new FeatureNotPresentImageException("Requested sector does not contain subchannel"); case TrackSubchannelType.RawInterleaved: sectorOffset = (uint)track.TrackRawBytesPerSector; sectorSize = 96; @@ -2338,7 +1891,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { if(ImageInfo.ReadableMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) return identify; @@ -2496,6 +2048,439 @@ namespace DiscImageChef.DiscImages return ReadSectorLong(GetAbsoluteSector(sectorAddress, track), length); } - #endregion Unsupported features + + 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 + } + + // Hunks are represented in a 64 bit integer with 44 bit as offset, 20 bits as length + // Sectors are fixed at 512 bytes/sector + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdHeaderV1 + { + /// <summary> + /// Magic identifier, 'MComprHD' + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; + /// <summary> + /// Length of header + /// </summary> + public uint length; + /// <summary> + /// Image format version + /// </summary> + public uint version; + /// <summary> + /// Image flags, <see cref="ChdFlags" /> + /// </summary> + public uint flags; + /// <summary> + /// Compression algorithm, <see cref="ChdCompression" /> + /// </summary> + public uint compression; + /// <summary> + /// Sectors per hunk + /// </summary> + public uint hunksize; + /// <summary> + /// Total # of hunk in image + /// </summary> + public uint totalhunks; + /// <summary> + /// Cylinders on disk + /// </summary> + public uint cylinders; + /// <summary> + /// Heads per cylinder + /// </summary> + public uint heads; + /// <summary> + /// Sectors per track + /// </summary> + public uint sectors; + /// <summary> + /// MD5 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; + /// <summary> + /// MD5 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; + } + + // Hunks are represented in a 64 bit integer with 44 bit as offset, 20 bits as length + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdHeaderV2 + { + /// <summary> + /// Magic identifier, 'MComprHD' + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; + /// <summary> + /// Length of header + /// </summary> + public uint length; + /// <summary> + /// Image format version + /// </summary> + public uint version; + /// <summary> + /// Image flags, <see cref="ChdFlags" /> + /// </summary> + public uint flags; + /// <summary> + /// Compression algorithm, <see cref="ChdCompression" /> + /// </summary> + public uint compression; + /// <summary> + /// Sectors per hunk + /// </summary> + public uint hunksize; + /// <summary> + /// Total # of hunk in image + /// </summary> + public uint totalhunks; + /// <summary> + /// Cylinders on disk + /// </summary> + public uint cylinders; + /// <summary> + /// Heads per cylinder + /// </summary> + public uint heads; + /// <summary> + /// Sectors per track + /// </summary> + public uint sectors; + /// <summary> + /// MD5 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; + /// <summary> + /// MD5 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; + /// <summary> + /// Bytes per sector + /// </summary> + public uint seclen; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdHeaderV3 + { + /// <summary> + /// Magic identifier, 'MComprHD' + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; + /// <summary> + /// Length of header + /// </summary> + public uint length; + /// <summary> + /// Image format version + /// </summary> + public uint version; + /// <summary> + /// Image flags, <see cref="ChdFlags" /> + /// </summary> + public uint flags; + /// <summary> + /// Compression algorithm, <see cref="ChdCompression" /> + /// </summary> + public uint compression; + /// <summary> + /// Total # of hunk in image + /// </summary> + public uint totalhunks; + /// <summary> + /// Total bytes in image + /// </summary> + public ulong logicalbytes; + /// <summary> + /// Offset to first metadata blob + /// </summary> + public ulong metaoffset; + /// <summary> + /// MD5 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] md5; + /// <summary> + /// MD5 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] parentmd5; + /// <summary> + /// Bytes per hunk + /// </summary> + public uint hunkbytes; + /// <summary> + /// SHA1 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; + /// <summary> + /// SHA1 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdMapV3Entry + { + /// <summary> + /// Offset to hunk from start of image + /// </summary> + public ulong offset; + /// <summary> + /// CRC32 of uncompressed hunk + /// </summary> + public uint crc; + /// <summary> + /// Lower 16 bits of length + /// </summary> + public ushort lengthLsb; + /// <summary> + /// Upper 8 bits of length + /// </summary> + public byte length; + /// <summary> + /// Hunk flags + /// </summary> + public byte flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdTrackOld + { + public uint type; + public uint subType; + public uint dataSize; + public uint subSize; + public uint frames; + public uint extraFrames; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdHeaderV4 + { + /// <summary> + /// Magic identifier, 'MComprHD' + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; + /// <summary> + /// Length of header + /// </summary> + public uint length; + /// <summary> + /// Image format version + /// </summary> + public uint version; + /// <summary> + /// Image flags, <see cref="ChdFlags" /> + /// </summary> + public uint flags; + /// <summary> + /// Compression algorithm, <see cref="ChdCompression" /> + /// </summary> + public uint compression; + /// <summary> + /// Total # of hunk in image + /// </summary> + public uint totalhunks; + /// <summary> + /// Total bytes in image + /// </summary> + public ulong logicalbytes; + /// <summary> + /// Offset to first metadata blob + /// </summary> + public ulong metaoffset; + /// <summary> + /// Bytes per hunk + /// </summary> + public uint hunkbytes; + /// <summary> + /// SHA1 of raw+meta data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; + /// <summary> + /// SHA1 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; + /// <summary> + /// SHA1 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] rawsha1; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdHeaderV5 + { + /// <summary> + /// Magic identifier, 'MComprHD' + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] tag; + /// <summary> + /// Length of header + /// </summary> + public uint length; + /// <summary> + /// Image format version + /// </summary> + public uint version; + /// <summary> + /// Compressor 0 + /// </summary> + public uint compressor0; + /// <summary> + /// Compressor 1 + /// </summary> + public uint compressor1; + /// <summary> + /// Compressor 2 + /// </summary> + public uint compressor2; + /// <summary> + /// Compressor 3 + /// </summary> + public uint compressor3; + /// <summary> + /// Total bytes in image + /// </summary> + public ulong logicalbytes; + /// <summary> + /// Offset to hunk map + /// </summary> + public ulong mapoffset; + /// <summary> + /// Offset to first metadata blob + /// </summary> + public ulong metaoffset; + /// <summary> + /// Bytes per hunk + /// </summary> + public uint hunkbytes; + /// <summary> + /// Bytes per unit within hunk + /// </summary> + public uint unitbytes; + /// <summary> + /// SHA1 of raw data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] rawsha1; + /// <summary> + /// SHA1 of raw+meta data + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sha1; + /// <summary> + /// SHA1 of parent file + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] parentsha1; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdCompressedMapHeaderV5 + { + /// <summary> + /// Length of compressed map + /// </summary> + public uint length; + /// <summary> + /// Offset of first block (48 bits) and CRC16 of map (16 bits) + /// </summary> + public ulong startAndCrc; + /// <summary> + /// Bits used to encode compressed length on map entry + /// </summary> + public byte bitsUsedToEncodeCompLength; + /// <summary> + /// Bits used to encode self-refs + /// </summary> + public byte bitsUsedToEncodeSelfRefs; + /// <summary> + /// Bits used to encode parent unit refs + /// </summary> + public byte bitsUsedToEncodeParentUnits; + public byte reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdMapV5Entry + { + /// <summary> + /// Compression (8 bits) and length (24 bits) + /// </summary> + public uint compAndLength; + /// <summary> + /// Offset (48 bits) and CRC (16 bits) + /// </summary> + public ulong offsetAndCrc; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChdMetadataHeader + { + public uint tag; + public uint flagsAndLength; + public ulong next; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HunkSector + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public ulong[] hunkEntry; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HunkSectorSmall + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public uint[] hunkEntry; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CPCDSK.cs b/DiscImageChef.DiscImages/CPCDSK.cs index 5b191f0fd..4e88325c3 100644 --- a/DiscImageChef.DiscImages/CPCDSK.cs +++ b/DiscImageChef.DiscImages/CPCDSK.cs @@ -45,9 +45,8 @@ namespace DiscImageChef.DiscImages { public class Cpcdsk : ImagePlugin { - #region Internal constants /// <summary> - /// Identifier for CPCEMU disk images, "MV - CPCEMU Disk-File" + /// Identifier for CPCEMU disk images, "MV - CPCEMU Disk-File" /// </summary> readonly byte[] cpcdskId = { @@ -55,7 +54,7 @@ namespace DiscImageChef.DiscImages 0x69, 0x6C, 0x65 }; /// <summary> - /// Identifier for DU54 disk images, "MV - CPC format Disk Image (DU54)" + /// Identifier for DU54 disk images, "MV - CPC format Disk Image (DU54)" /// </summary> readonly byte[] du54Id = { @@ -63,7 +62,7 @@ namespace DiscImageChef.DiscImages 0x73, 0x6B, 0x20 }; /// <summary> - /// Identifier for Extended CPCEMU disk images, "EXTENDED CPC DSK File" + /// Identifier for Extended CPCEMU disk images, "EXTENDED CPC DSK File" /// </summary> readonly byte[] edskId = { @@ -71,137 +70,13 @@ namespace DiscImageChef.DiscImages 0x69, 0x6C, 0x65 }; /// <summary> - /// Identifier for track information, "Track-Info\r\n" + /// Identifier for track information, "Track-Info\r\n" /// </summary> readonly byte[] trackId = {0x54, 0x72, 0x61, 0x63, 0x6B, 0x2D, 0x49, 0x6E, 0x66, 0x6F}; - #endregion + Dictionary<ulong, byte[]> addressMarks; - #region Internal structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CpcDiskInfo - { - /// <summary> - /// Magic number, "MV - CPCEMU Disk-File" in old files, "EXTENDED CPC DSK File" in extended ones - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)] public byte[] magic; - /// <summary> - /// Second part of magic, should be "\r\nDisk-Info\r\n" in all, but some emulators write spaces instead. - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte[] magic2; - /// <summary> - /// Creator application (can be null) - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] creator; - /// <summary> - /// Tracks - /// </summary> - public byte tracks; - /// <summary> - /// Sides - /// </summary> - public byte sides; - /// <summary> - /// Size of a track including the 256 bytes header. Unused by extended format, as this format includes a table in the next field - /// </summary> - public ushort tracksize; - /// <summary> - /// Size of each track in the extended format. 0 indicates track is not formatted and not present in image. - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 204)] public byte[] tracksizeTable; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CpcTrackInfo - { - /// <summary> - /// Magic number, "Track-Info\r\n" - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] magic; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] carriageReturn; - /// <summary> - /// Padding - /// </summary> - public uint padding; - /// <summary> - /// Track number - /// </summary> - public byte track; - /// <summary> - /// Side number - /// </summary> - public byte side; - /// <summary> - /// Controller data rate - /// </summary> - public byte dataRate; - /// <summary> - /// Recording mode - /// </summary> - public byte recordingMode; - /// <summary> - /// Bytes per sector - /// </summary> - public IBMSectorSizeCode bps; - /// <summary> - /// How many sectors in this track - /// </summary> - public byte sectors; - /// <summary> - /// GAP#3 - /// </summary> - public byte gap3; - /// <summary> - /// Filler - /// </summary> - public byte filler; - /// <summary> - /// Informatino for up to 32 sectors - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public CpcSectorInfo[] sectorsInfo; - } - - /// <summary> - /// Sector information - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CpcSectorInfo - { - /// <summary> - /// Track number from address mark - /// </summary> - public byte track; - /// <summary> - /// Side number from address mark - /// </summary> - public byte side; - /// <summary> - /// Sector ID from address mark - /// </summary> - public byte id; - /// <summary> - /// Sector size from address mark - /// </summary> - public IBMSectorSizeCode size; - /// <summary> - /// ST1 register from controller - /// </summary> - public byte st1; - /// <summary> - /// ST2 register from controller - /// </summary> - public byte st2; - /// <summary> - /// Length in bytes of this sector size. If it is bigger than expected sector size, it's a weak sector read several times. - /// </summary> - public ushort len; - } - #endregion - - #region Internal variables bool extended; Dictionary<ulong, byte[]> sectors; - Dictionary<ulong, byte[]> addressMarks; - #endregion public Cpcdsk() { @@ -364,7 +239,9 @@ namespace DiscImageChef.DiscImages trackInfo.sectorsInfo[k - 1].track, i, j, k); int sectLen; - sectLen = extended ? trackInfo.sectorsInfo[k - 1].len : SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size); + sectLen = extended + ? trackInfo.sectorsInfo[k - 1].len + : SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size); byte[] sector = new byte[sectLen]; stream.Read(sector, 0, sectLen); @@ -606,7 +483,6 @@ namespace DiscImageChef.DiscImages return ms.ToArray(); } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -757,6 +633,126 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CpcDiskInfo + { + /// <summary> + /// Magic number, "MV - CPCEMU Disk-File" in old files, "EXTENDED CPC DSK File" in extended ones + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)] public byte[] magic; + /// <summary> + /// Second part of magic, should be "\r\nDisk-Info\r\n" in all, but some emulators write spaces instead. + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte[] magic2; + /// <summary> + /// Creator application (can be null) + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] creator; + /// <summary> + /// Tracks + /// </summary> + public byte tracks; + /// <summary> + /// Sides + /// </summary> + public byte sides; + /// <summary> + /// Size of a track including the 256 bytes header. Unused by extended format, as this format includes a table in the + /// next field + /// </summary> + public ushort tracksize; + /// <summary> + /// Size of each track in the extended format. 0 indicates track is not formatted and not present in image. + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 204)] public byte[] tracksizeTable; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CpcTrackInfo + { + /// <summary> + /// Magic number, "Track-Info\r\n" + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] magic; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] carriageReturn; + /// <summary> + /// Padding + /// </summary> + public uint padding; + /// <summary> + /// Track number + /// </summary> + public byte track; + /// <summary> + /// Side number + /// </summary> + public byte side; + /// <summary> + /// Controller data rate + /// </summary> + public byte dataRate; + /// <summary> + /// Recording mode + /// </summary> + public byte recordingMode; + /// <summary> + /// Bytes per sector + /// </summary> + public IBMSectorSizeCode bps; + /// <summary> + /// How many sectors in this track + /// </summary> + public byte sectors; + /// <summary> + /// GAP#3 + /// </summary> + public byte gap3; + /// <summary> + /// Filler + /// </summary> + public byte filler; + /// <summary> + /// Informatino for up to 32 sectors + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public CpcSectorInfo[] sectorsInfo; + } + + /// <summary> + /// Sector information + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CpcSectorInfo + { + /// <summary> + /// Track number from address mark + /// </summary> + public byte track; + /// <summary> + /// Side number from address mark + /// </summary> + public byte side; + /// <summary> + /// Sector ID from address mark + /// </summary> + public byte id; + /// <summary> + /// Sector size from address mark + /// </summary> + public IBMSectorSizeCode size; + /// <summary> + /// ST1 register from controller + /// </summary> + public byte st1; + /// <summary> + /// ST2 register from controller + /// </summary> + public byte st2; + /// <summary> + /// Length in bytes of this sector size. If it is bigger than expected sector size, it's a weak sector read several + /// times. + /// </summary> + public ushort len; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CisCopy.cs b/DiscImageChef.DiscImages/CisCopy.cs index 29316f4a0..c0680f946 100644 --- a/DiscImageChef.DiscImages/CisCopy.cs +++ b/DiscImageChef.DiscImages/CisCopy.cs @@ -57,37 +57,7 @@ namespace DiscImageChef.DiscImages */ public class CisCopy : ImagePlugin { - #region Internal enumerations - [SuppressMessage("ReSharper", "InconsistentNaming")] - enum DiskType : byte - { - MD1DD8 = 1, - MD1DD = 2, - MD2DD8 = 3, - MD2DD = 4, - MF2DD = 5, - MD2HD = 6, - MF2HD = 7 - } - - enum Compression : byte - { - None = 0, - Normal = 1, - High = 2 - } - - enum TrackType : byte - { - Copied = 0x4C, - Omitted = 0xFA, - OmittedAlternate = 0xFE - } - #endregion Internal enumeration - - #region Internal variables byte[] decodedDisk; - #endregion Internal variables public CisCopy() { @@ -118,7 +88,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -510,9 +479,7 @@ namespace DiscImageChef.DiscImages { return ImageInfo.DriveSerialNumber; } - #endregion Public methods - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -592,6 +559,31 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum DiskType : byte + { + MD1DD8 = 1, + MD1DD = 2, + MD2DD8 = 3, + MD2DD = 4, + MF2DD = 5, + MD2HD = 6, + MF2HD = 7 + } + + enum Compression : byte + { + None = 0, + Normal = 1, + High = 2 + } + + enum TrackType : byte + { + Copied = 0x4C, + Omitted = 0xFA, + OmittedAlternate = 0xFE + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/CloneCD.cs b/DiscImageChef.DiscImages/CloneCD.cs index dbbfb6f30..fff8c56ff 100644 --- a/DiscImageChef.DiscImages/CloneCD.cs +++ b/DiscImageChef.DiscImages/CloneCD.cs @@ -45,7 +45,6 @@ namespace DiscImageChef.DiscImages { public class CloneCd : ImagePlugin { - #region Parsing regexs const string CCD_IDENTIFIER = "^\\s*\\[CloneCD\\]"; const string DISC_IDENTIFIER = "^\\s*\\[Disc\\]"; const string SESSION_IDENTIFIER = "^\\s*\\[Session\\s*(?<number>\\d+)\\]"; @@ -76,22 +75,21 @@ namespace DiscImageChef.DiscImages const string ENTRY_PLBA = "^\\s*PLBA\\s*=\\s*(?<value>\\d+)"; const string CDTEXT_ENTRIES = "^\\s*Entries\\s*=\\s*(?<value>\\d+)"; const string CDTEXT_ENTRY = "^\\s*Entry\\s*(?<number>\\d+)\\s*=\\s*(?<value>([0-9a-fA-F]+\\s*)+)"; - #endregion + string catalog; // TODO: Use it Filter ccdFilter; - Filter dataFilter; - Filter subFilter; - StreamReader cueStream; - byte[] fulltoc; - bool scrambled; - string catalog; // TODO: Use it - List<Session> sessions; - List<Partition> partitions; - List<Track> tracks; - Stream dataStream; - Stream subStream; - Dictionary<uint, ulong> offsetmap; byte[] cdtext; + StreamReader cueStream; + Filter dataFilter; + Stream dataStream; + byte[] fulltoc; + Dictionary<uint, ulong> offsetmap; + List<Partition> partitions; + bool scrambled; + List<Session> sessions; + Filter subFilter; + Stream subStream; + List<Track> tracks; public CloneCd() { @@ -289,15 +287,19 @@ namespace DiscImageChef.DiscImages Match cdtLenMatch = cdtLenRegex.Match(line); Match discCatMatch = discCatRegex.Match(line); - if(discEntMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found TocEntries at line {0}", lineNumber); - else if(discSessMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found Sessions at line {0}", lineNumber); + if(discEntMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found TocEntries at line {0}", lineNumber); + else if(discSessMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found Sessions at line {0}", lineNumber); else if(discScrMatch.Success) { DicConsole.DebugWriteLine("CloneCD plugin", "Found DataTracksScrambled at line {0}", lineNumber); scrambled |= discScrMatch.Groups["value"].Value == "1"; } - else if(cdtLenMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found CDTextLength at line {0}", lineNumber); + else if(cdtLenMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found CDTextLength at line {0}", + lineNumber); else if(discCatMatch.Success) { DicConsole.DebugWriteLine("CloneCD plugin", "Found Catalog at line {0}", lineNumber); @@ -310,13 +312,16 @@ namespace DiscImageChef.DiscImages Match cdtEntsMatch = cdtEntsRegex.Match(line); Match cdtEntMatch = cdtEntRegex.Match(line); - if(cdtEntsMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entries at line {0}", lineNumber); + if(cdtEntsMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entries at line {0}", + lineNumber); else if(cdtEntMatch.Success) { - DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entry at line {0}", lineNumber); + DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entry at line {0}", + lineNumber); string[] bytes = cdtEntMatch.Groups["value"].Value.Split(new[] {' '}, - StringSplitOptions - .RemoveEmptyEntries); + StringSplitOptions + .RemoveEmptyEntries); foreach(string byt in bytes) cdtMs.WriteByte(Convert.ToByte(byt, 16)); } } @@ -326,8 +331,10 @@ namespace DiscImageChef.DiscImages Match sessPregMatch = sessPregRegex.Match(line); Match sessSubcMatch = sessSubcRegex.Match(line); - if(sessPregMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapMode at line {0}", lineNumber); - else if(sessSubcMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapSubC at line {0}", lineNumber); + if(sessPregMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapMode at line {0}", lineNumber); + else if(sessSubcMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapSubC at line {0}", lineNumber); } else if(inEntry) { @@ -388,7 +395,8 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("CloneCD plugin", "Found AFrame at line {0}", lineNumber); currentEntry.Frame = Convert.ToByte(entAFrameMatch.Groups["value"].Value, 10); } - else if(entAlbaMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found ALBA at line {0}", lineNumber); + else if(entAlbaMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found ALBA at line {0}", lineNumber); else if(entZeroMatch.Success) { DicConsole.DebugWriteLine("CloneCD plugin", "Found Zero at line {0}", lineNumber); @@ -411,7 +419,8 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("CloneCD plugin", "Found PFrame at line {0}", lineNumber); currentEntry.PFRAME = Convert.ToByte(entPFrameMatch.Groups["value"].Value, 10); } - else if(entPlbaMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PLBA at line {0}", lineNumber); + else if(entPlbaMatch.Success) + DicConsole.DebugWriteLine("CloneCD plugin", "Found PLBA at line {0}", lineNumber); } } } @@ -562,11 +571,11 @@ namespace DiscImageChef.DiscImages ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader); if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEcc) ) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEcc); - if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType - .CdSectorEccP)) + if(!ImageInfo.ReadableSectorTags + .Contains(SectorTagType.CdSectorEccP)) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccP); - if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType - .CdSectorEccQ)) + if(!ImageInfo.ReadableSectorTags + .Contains(SectorTagType.CdSectorEccQ)) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccQ); if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc) ) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc); @@ -882,14 +891,26 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress <= track.TrackEndSector select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress <= track.TrackEndSector + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress <= track.TrackEndSector select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress <= track.TrackEndSector + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -898,7 +919,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -979,7 +1001,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -1226,7 +1249,14 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector + 1 select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + 1 + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -1235,7 +1265,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -1420,9 +1451,7 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, @@ -1451,9 +1480,7 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() diff --git a/DiscImageChef.DiscImages/CopyQM.cs b/DiscImageChef.DiscImages/CopyQM.cs index e42d15cab..aa594c5aa 100644 --- a/DiscImageChef.DiscImages/CopyQM.cs +++ b/DiscImageChef.DiscImages/CopyQM.cs @@ -42,76 +42,6 @@ namespace DiscImageChef.DiscImages { public class CopyQm : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CopyQmHeader - { - /// <summary>0x00 magic, "CQ"</summary> - public ushort magic; - /// <summary>0x02 always 0x14</summary> - public byte mark; - /// <summary>0x03 Bytes per sector (part of FAT's BPB)</summary> - public ushort sectorSize; - /// <summary>0x05 Sectors per cluster (part of FAT's BPB)</summary> - public byte sectorPerCluster; - /// <summary>0x06 Reserved sectors (part of FAT's BPB)</summary> - public ushort reservedSectors; - /// <summary>0x08 Number of FAT copies (part of FAT's BPB)</summary> - public byte fatCopy; - /// <summary>0x09 Maximum number of entries in root directory (part of FAT's BPB)</summary> - public ushort rootEntries; - /// <summary>0x0B Sectors on disk (part of FAT's BPB)</summary> - public ushort sectors; - /// <summary>0x0D Media descriptor (part of FAT's BPB)</summary> - public byte mediaType; - /// <summary>0x0E Sectors per FAT (part of FAT's BPB)</summary> - public ushort sectorsPerFat; - /// <summary>0x10 Sectors per track (part of FAT's BPB)</summary> - public ushort sectorsPerTrack; - /// <summary>0x12 Heads (part of FAT's BPB)</summary> - public ushort heads; - /// <summary>0x14 Hidden sectors (part of FAT's BPB)</summary> - public uint hidden; - /// <summary>0x18 Sectors on disk (part of FAT's BPB)</summary> - public uint sectorsBig; - /// <summary>0x1C Description</summary> - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)] public string description; - /// <summary>0x58 Blind mode. 0 = DOS, 1 = blind, 2 = HFS</summary> - public byte blind; - /// <summary>0x59 Density. 0 = Double, 1 = High, 2 = Quad/Extra</summary> - public byte density; - /// <summary>0x5A Cylinders in image</summary> - public byte imageCylinders; - /// <summary>0x5B Cylinders on disk</summary> - public byte totalCylinders; - /// <summary>0x5C CRC32 of data</summary> - public uint crc; - /// <summary>0x60 DOS volume label</summary> - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string volumeLabel; - /// <summary>0x6B Modification time</summary> - public ushort time; - /// <summary>0x6D Modification date</summary> - public ushort date; - /// <summary>0x6F Comment length</summary> - public ushort commentLength; - /// <summary>0x71 Sector base (first sector - 1)</summary> - public byte secbs; - /// <summary>0x72 Unknown</summary> - public ushort unknown; - /// <summary>0x74 Interleave</summary> - public byte interleave; - /// <summary>0x75 Skew</summary> - public byte skew; - /// <summary>0x76 Source drive type. 1 = 5.25" DD, 2 = 5.25" HD, 3 = 3.5" DD, 4 = 3.5" HD, 6 = 3.5" ED</summary> - public byte drive; - /// <summary>0x77 Filling bytes</summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte[] fill; - /// <summary>0x84 Header checksum</summary> - public byte headerChecksum; - } - #endregion Internal Structures - - #region Internal Constants const ushort COPYQM_MAGIC = 0x5143; const byte COPYQM_MARK = 0x14; @@ -157,16 +87,13 @@ namespace DiscImageChef.DiscImages 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; - #endregion Internal Constants - - #region Internal variables - CopyQmHeader header; + uint calculatedDataCrc; byte[] decodedDisk; MemoryStream decodedImage; + CopyQmHeader header; + bool headerChecksumOk; - uint calculatedDataCrc; - #endregion Internal variables public CopyQm() { @@ -197,7 +124,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -209,9 +135,7 @@ namespace DiscImageChef.DiscImages ushort magic = BitConverter.ToUInt16(hdr, 0); - if(magic != COPYQM_MAGIC || hdr[0x02] != COPYQM_MARK || 133 + hdr[0x6F] >= stream.Length) return false; - - return true; + return magic == COPYQM_MAGIC && hdr[0x02] == COPYQM_MARK && 133 + hdr[0x6F] < stream.Length; } public override bool OpenImage(Filter imageFilter) @@ -291,8 +215,8 @@ namespace DiscImageChef.DiscImages stream.Read(nonRepeated, 0, runLength); decodedImage.Write(nonRepeated, 0, runLength); - foreach(byte c in nonRepeated) calculatedDataCrc = copyQmCrcTable[(c ^ calculatedDataCrc) & 0x3F] ^ - (calculatedDataCrc >> 8); + foreach(byte c in nonRepeated) + calculatedDataCrc = copyQmCrcTable[(c ^ calculatedDataCrc) & 0x3F] ^ (calculatedDataCrc >> 8); } } @@ -319,8 +243,8 @@ namespace DiscImageChef.DiscImages headerChecksumOk = ((-1 * sum) & 0xFF) == header.headerChecksum; - DicConsole.DebugWriteLine("CopyQM plugin", "Calculated header checksum = 0x{0:X2}, {1}", - (-1 * sum) & 0xFF, headerChecksumOk); + DicConsole.DebugWriteLine("CopyQM plugin", "Calculated header checksum = 0x{0:X2}, {1}", (-1 * sum) & 0xFF, + headerChecksumOk); DicConsole.DebugWriteLine("CopyQM plugin", "Calculated data CRC = 0x{0:X8}, {1}", calculatedDataCrc, calculatedDataCrc == header.crc); @@ -599,9 +523,7 @@ namespace DiscImageChef.DiscImages { return ImageInfo.DriveSerialNumber; } - #endregion Public methods - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -681,6 +603,72 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CopyQmHeader + { + /// <summary>0x00 magic, "CQ"</summary> + public ushort magic; + /// <summary>0x02 always 0x14</summary> + public byte mark; + /// <summary>0x03 Bytes per sector (part of FAT's BPB)</summary> + public ushort sectorSize; + /// <summary>0x05 Sectors per cluster (part of FAT's BPB)</summary> + public byte sectorPerCluster; + /// <summary>0x06 Reserved sectors (part of FAT's BPB)</summary> + public ushort reservedSectors; + /// <summary>0x08 Number of FAT copies (part of FAT's BPB)</summary> + public byte fatCopy; + /// <summary>0x09 Maximum number of entries in root directory (part of FAT's BPB)</summary> + public ushort rootEntries; + /// <summary>0x0B Sectors on disk (part of FAT's BPB)</summary> + public ushort sectors; + /// <summary>0x0D Media descriptor (part of FAT's BPB)</summary> + public byte mediaType; + /// <summary>0x0E Sectors per FAT (part of FAT's BPB)</summary> + public ushort sectorsPerFat; + /// <summary>0x10 Sectors per track (part of FAT's BPB)</summary> + public ushort sectorsPerTrack; + /// <summary>0x12 Heads (part of FAT's BPB)</summary> + public ushort heads; + /// <summary>0x14 Hidden sectors (part of FAT's BPB)</summary> + public uint hidden; + /// <summary>0x18 Sectors on disk (part of FAT's BPB)</summary> + public uint sectorsBig; + /// <summary>0x1C Description</summary> + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)] public string description; + /// <summary>0x58 Blind mode. 0 = DOS, 1 = blind, 2 = HFS</summary> + public byte blind; + /// <summary>0x59 Density. 0 = Double, 1 = High, 2 = Quad/Extra</summary> + public byte density; + /// <summary>0x5A Cylinders in image</summary> + public byte imageCylinders; + /// <summary>0x5B Cylinders on disk</summary> + public byte totalCylinders; + /// <summary>0x5C CRC32 of data</summary> + public uint crc; + /// <summary>0x60 DOS volume label</summary> + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string volumeLabel; + /// <summary>0x6B Modification time</summary> + public ushort time; + /// <summary>0x6D Modification date</summary> + public ushort date; + /// <summary>0x6F Comment length</summary> + public ushort commentLength; + /// <summary>0x71 Sector base (first sector - 1)</summary> + public byte secbs; + /// <summary>0x72 Unknown</summary> + public ushort unknown; + /// <summary>0x74 Interleave</summary> + public byte interleave; + /// <summary>0x75 Skew</summary> + public byte skew; + /// <summary>0x76 Source drive type. 1 = 5.25" DD, 2 = 5.25" HD, 3 = 3.5" DD, 4 = 3.5" HD, 6 = 3.5" ED</summary> + public byte drive; + /// <summary>0x77 Filling bytes</summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte[] fill; + /// <summary>0x84 Header checksum</summary> + public byte headerChecksum; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/D88.cs b/DiscImageChef.DiscImages/D88.cs index d79ad8c44..bac8fb8a1 100644 --- a/DiscImageChef.DiscImages/D88.cs +++ b/DiscImageChef.DiscImages/D88.cs @@ -47,155 +47,9 @@ namespace DiscImageChef.DiscImages // Japanese comments copied from there public class D88 : ImagePlugin { - #region Internal enumerations - enum DiskType : byte - { - D2 = 0x00, - Dd2 = 0x10, - Hd2 = 0x20 - } - - enum DensityType : byte - { - Mfm = 0x00, - Fm = 0x40 - } - - /// <summary> - /// Status as returned by PC-98 BIOS - /// ステータスは、PC-98x1 のBIOS が返してくるステータスで、 - /// </summary> - enum StatusType : byte - { - /// <summary> - /// Normal - /// 正常 - /// </summary> - Normal = 0x00, - /// <summary> - /// Deleted - /// 正常(DELETED DATA) - /// </summary> - Deleted = 0x10, - /// <summary> - /// CRC error in address fields - /// ID CRC エラー - /// </summary> - IdError = 0xA0, - /// <summary> - /// CRC error in data block - /// データ CRC エラー - /// </summary> - DataError = 0xB0, - /// <summary> - /// Address mark not found - /// アドレスマークなし - /// </summary> - AddressMarkNotFound = 0xE0, - /// <summary> - /// Data mark not found - /// データマークなし - /// </summary> - DataMarkNotFound = 0xF0 - } - #endregion - - #region Internal constants - readonly byte[] reservedEmpty = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const byte READ_ONLY = 0x10; - #endregion - #region Internal structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct D88Header - { - /// <summary> - /// Disk name, nul-terminated ASCII - /// ディスクの名前(ASCII + '\0') - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] public byte[] name; - /// <summary> - /// Reserved - /// ディスクの名前(ASCII + '\0') - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] reserved; - /// <summary> - /// Write protect status - /// ライトプロテクト: 0x00 なし、0x10 あり - /// </summary> - public byte write_protect; - /// <summary> - /// Disk type - /// ディスクの種類: 0x00 2D、 0x10 2DD、 0x20 2HD - /// </summary> - public DiskType disk_type; - /// <summary> - /// Disk image size - /// ディスクのサイズ - /// </summary> - public int disk_size; - /// <summary> - /// Track pointers - /// トラック部のオフセットテーブル 0 Track ~ 163 Track - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 164)] public int[] track_table; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SectorHeader - { - /// <summary> - /// Cylinder - /// ID の C - /// </summary> - public byte c; - /// <summary> - /// Head - /// ID の H - /// </summary> - public byte h; - /// <summary> - /// Sector number - /// ID の R - /// </summary> - public byte r; - /// <summary> - /// Sector size - /// ID の N - /// </summary> - public IBMSectorSizeCode n; - /// <summary> - /// Number of sectors in this track - /// このトラック内に存在するセクタの数 - /// </summary> - public short spt; - /// <summary> - /// Density: 0x00 MFM, 0x40 FM - /// 記録密度: 0x00 倍密度、0x40 単密度 - /// </summary> - public DensityType density; - /// <summary> - /// Deleted sector, 0x00 not deleted, 0x10 deleted - /// DELETED MARK: 0x00 ノーマル、 0x10 DELETED - /// </summary> - public byte deleted_mark; - /// <summary> - /// Sector status - /// ステータス - /// </summary> - public byte status; - /// <summary> - /// Reserved - /// リザーブ - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] reserved; - /// <summary> - /// Size of data following this field - /// このセクタ部のデータサイズ - /// </summary> - public short size_of_data; - } - #endregion + readonly byte[] reservedEmpty = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; List<byte[]> sectorsData; @@ -263,7 +117,8 @@ namespace DiscImageChef.DiscImages if(!d88Hdr.reserved.SequenceEqual(reservedEmpty)) return false; int counter = 0; - foreach(int t in d88Hdr.track_table) { + foreach(int t in d88Hdr.track_table) + { if(t > 0) counter++; if(t < 0 || t > stream.Length) return false; @@ -309,11 +164,11 @@ namespace DiscImageChef.DiscImages if(!d88Hdr.reserved.SequenceEqual(reservedEmpty)) return false; int trkCounter = 0; - for(int i = 0; i < d88Hdr.track_table.Length; i++) + foreach(int t in d88Hdr.track_table) { - if(d88Hdr.track_table[i] > 0) trkCounter++; + if(t > 0) trkCounter++; - if(d88Hdr.track_table[i] < 0 || d88Hdr.track_table[i] > stream.Length) return false; + if(t < 0 || t > stream.Length) return false; } DicConsole.DebugWriteLine("D88 plugin", "{0} tracks", trkCounter); @@ -390,7 +245,7 @@ namespace DiscImageChef.DiscImages foreach(KeyValuePair<byte, byte[]> kvp in sectors) sectorsData.Add(kvp.Value); } - DicConsole.DebugWriteLine("D88 plugin", "{0} sectors", sectorsData.Count()); + DicConsole.DebugWriteLine("D88 plugin", "{0} sectors", sectorsData.Count); /* FileStream debugStream = new FileStream("debug.img", FileMode.CreateNew, FileAccess.ReadWrite); @@ -404,16 +259,18 @@ namespace DiscImageChef.DiscImages if(trkCounter == 154 && spt == 26 && bps == IBMSectorSizeCode.EighthKilo) ImageInfo.MediaType = MediaType.NEC_8_SD; else if(bps == IBMSectorSizeCode.QuarterKilo) - { - switch(trkCounter) { - case 80 when spt == 16: ImageInfo.MediaType = MediaType.NEC_525_SS; + switch(trkCounter) + { + case 80 when spt == 16: + ImageInfo.MediaType = MediaType.NEC_525_SS; break; - case 154 when spt == 26: ImageInfo.MediaType = MediaType.NEC_8_DD; + case 154 when spt == 26: + ImageInfo.MediaType = MediaType.NEC_8_DD; break; - case 160 when spt == 16: ImageInfo.MediaType = MediaType.NEC_525_DS; + case 160 when spt == 16: + ImageInfo.MediaType = MediaType.NEC_525_DS; break; } - } else if(trkCounter == 154 && spt == 8 && bps == IBMSectorSizeCode.Kilo) ImageInfo.MediaType = MediaType.NEC_525_HD; else if(bps == IBMSectorSizeCode.HalfKilo) @@ -646,7 +503,6 @@ namespace DiscImageChef.DiscImages return buffer.ToArray(); } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -807,6 +663,146 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + enum DiskType : byte + { + D2 = 0x00, + Dd2 = 0x10, + Hd2 = 0x20 + } + + enum DensityType : byte + { + Mfm = 0x00, + Fm = 0x40 + } + + /// <summary> + /// Status as returned by PC-98 BIOS + /// ステータスは、PC-98x1 のBIOS が返してくるステータスで、 + /// </summary> + enum StatusType : byte + { + /// <summary> + /// Normal + /// 正常 + /// </summary> + Normal = 0x00, + /// <summary> + /// Deleted + /// 正常(DELETED DATA) + /// </summary> + Deleted = 0x10, + /// <summary> + /// CRC error in address fields + /// ID CRC エラー + /// </summary> + IdError = 0xA0, + /// <summary> + /// CRC error in data block + /// データ CRC エラー + /// </summary> + DataError = 0xB0, + /// <summary> + /// Address mark not found + /// アドレスマークなし + /// </summary> + AddressMarkNotFound = 0xE0, + /// <summary> + /// Data mark not found + /// データマークなし + /// </summary> + DataMarkNotFound = 0xF0 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct D88Header + { + /// <summary> + /// Disk name, nul-terminated ASCII + /// ディスクの名前(ASCII + '\0') + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] public byte[] name; + /// <summary> + /// Reserved + /// ディスクの名前(ASCII + '\0') + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] reserved; + /// <summary> + /// Write protect status + /// ライトプロテクト: 0x00 なし、0x10 あり + /// </summary> + public byte write_protect; + /// <summary> + /// Disk type + /// ディスクの種類: 0x00 2D、 0x10 2DD、 0x20 2HD + /// </summary> + public DiskType disk_type; + /// <summary> + /// Disk image size + /// ディスクのサイズ + /// </summary> + public int disk_size; + /// <summary> + /// Track pointers + /// トラック部のオフセットテーブル 0 Track ~ 163 Track + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 164)] public int[] track_table; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SectorHeader + { + /// <summary> + /// Cylinder + /// ID の C + /// </summary> + public byte c; + /// <summary> + /// Head + /// ID の H + /// </summary> + public byte h; + /// <summary> + /// Sector number + /// ID の R + /// </summary> + public byte r; + /// <summary> + /// Sector size + /// ID の N + /// </summary> + public IBMSectorSizeCode n; + /// <summary> + /// Number of sectors in this track + /// このトラック内に存在するセクタの数 + /// </summary> + public short spt; + /// <summary> + /// Density: 0x00 MFM, 0x40 FM + /// 記録密度: 0x00 倍密度、0x40 単密度 + /// </summary> + public DensityType density; + /// <summary> + /// Deleted sector, 0x00 not deleted, 0x10 deleted + /// DELETED MARK: 0x00 ノーマル、 0x10 DELETED + /// </summary> + public byte deleted_mark; + /// <summary> + /// Sector status + /// ステータス + /// </summary> + public byte status; + /// <summary> + /// Reserved + /// リザーブ + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] reserved; + /// <summary> + /// Size of data following this field + /// このセクタ部のデータサイズ + /// </summary> + public short size_of_data; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DART.cs b/DiscImageChef.DiscImages/DART.cs index 61441e468..c677d7b18 100644 --- a/DiscImageChef.DiscImages/DART.cs +++ b/DiscImageChef.DiscImages/DART.cs @@ -46,7 +46,6 @@ namespace DiscImageChef.DiscImages { public class Dart : ImagePlugin { - #region Internal constants // Disk types const byte DISK_MAC = 1; const byte DISK_LISA = 2; @@ -82,22 +81,11 @@ namespace DiscImageChef.DiscImages const int DATA_SIZE = SECTORS_PER_BLOCK * SECTOR_SIZE; const int TAG_SIZE = SECTORS_PER_BLOCK * TAG_SECTOR_SIZE; const int BUFFER_SIZE = SECTORS_PER_BLOCK * SECTOR_SIZE + SECTORS_PER_BLOCK * TAG_SECTOR_SIZE; - #endregion - - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct DartHeader - { - public byte srcCmp; - public byte srcType; - public short srcSize; - } - #endregion // DART images are at most 1474560 bytes, so let's cache the whole byte[] dataCache; - byte[] tagCache; uint dataChecksum; + byte[] tagCache; uint tagChecksum; public Dart() @@ -177,9 +165,7 @@ namespace DiscImageChef.DiscImages default: return false; } - if(stream.Length > expectedMaxSize) return false; - - return true; + return stream.Length <= expectedMaxSize; } public override bool OpenImage(Filter imageFilter) @@ -234,7 +220,8 @@ namespace DiscImageChef.DiscImages short[] bLength; - if(header.srcType == DISK_MAC_HD || header.srcType == DISK_DOS_HD) bLength = new short[BLOCK_ARRAY_LEN_HIGH]; + if(header.srcType == DISK_MAC_HD || header.srcType == DISK_DOS_HD) + bLength = new short[BLOCK_ARRAY_LEN_HIGH]; else bLength = new short[BLOCK_ARRAY_LEN_LOW]; for(int i = 0; i < bLength.Length; i++) @@ -247,32 +234,31 @@ namespace DiscImageChef.DiscImages MemoryStream dataMs = new MemoryStream(); MemoryStream tagMs = new MemoryStream(); - foreach(short l in bLength) if(l != 0) - { - byte[] buffer = new byte[BUFFER_SIZE]; - if(l == -1) + foreach(short l in bLength) + if(l != 0) { - stream.Read(buffer, 0, BUFFER_SIZE); - dataMs.Write(buffer, 0, DATA_SIZE); - tagMs.Write(buffer, DATA_SIZE, TAG_SIZE); - } - else - { - byte[] temp; - if(header.srcCmp == COMPRESS_RLE) + byte[] buffer = new byte[BUFFER_SIZE]; + if(l == -1) { - temp = new byte[l * 2]; - stream.Read(temp, 0, temp.Length); - throw new ImageNotSupportedException("Compressed images not yet supported"); + stream.Read(buffer, 0, BUFFER_SIZE); + dataMs.Write(buffer, 0, DATA_SIZE); + tagMs.Write(buffer, DATA_SIZE, TAG_SIZE); } else { + byte[] temp; + if(header.srcCmp == COMPRESS_RLE) + { + temp = new byte[l * 2]; + stream.Read(temp, 0, temp.Length); + throw new ImageNotSupportedException("Compressed images not yet supported"); + } + temp = new byte[l]; stream.Read(temp, 0, temp.Length); throw new ImageNotSupportedException("Compressed images not yet supported"); } } - } dataCache = dataMs.ToArray(); if(header.srcType == DISK_LISA || header.srcType == DISK_MAC || header.srcType == DISK_APPLE2) @@ -303,8 +289,7 @@ namespace DiscImageChef.DiscImages string major = $"{version.MajorVersion}"; string minor = $".{version.MinorVersion / 10}"; - if(version.MinorVersion % 10 > 0) - release = $".{version.MinorVersion % 10}"; + if(version.MinorVersion % 10 > 0) release = $".{version.MinorVersion % 10}"; switch(version.DevStage) { case Version.DevelopmentStage.Alpha: @@ -336,7 +321,8 @@ namespace DiscImageChef.DiscImages { string dArt = StringHandlers.PascalToString(dartRsrc.GetResource(dartRsrc.GetIds()[0]), Encoding.GetEncoding("macintosh")); - const string DART_REGEX = "(?<version>\\S+), tag checksum=\\$(?<tagchk>[0123456789ABCDEF]{8}), data checksum=\\$(?<datachk>[0123456789ABCDEF]{8})$"; + const string DART_REGEX = + "(?<version>\\S+), tag checksum=\\$(?<tagchk>[0123456789ABCDEF]{8}), data checksum=\\$(?<datachk>[0123456789ABCDEF]{8})$"; Regex dArtEx = new Regex(DART_REGEX); Match dArtMatch = dArtEx.Match(dArt); @@ -556,7 +542,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -697,6 +682,13 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DartHeader + { + public byte srcCmp; + public byte srcType; + public short srcSize; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DIM.cs b/DiscImageChef.DiscImages/DIM.cs index 561a8dbcb..59f57b97e 100644 --- a/DiscImageChef.DiscImages/DIM.cs +++ b/DiscImageChef.DiscImages/DIM.cs @@ -43,31 +43,15 @@ namespace DiscImageChef.DiscImages { public class Dim : ImagePlugin { - #region Internal enumerations - enum DiskType : byte - { - Hd2 = 0, - Hs2 = 1, - Hc2 = 2, - Hde2 = 3, - Hq2 = 9, - N88 = 17 - } - #endregion - - #region Internal constants - readonly byte[] headerId = {0x44, 0x49, 0x46, 0x43, 0x20, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x20}; - #endregion - - #region Internal variables /// <summary>Start of data sectors in disk image, should be 0x100</summary> const uint DATA_OFFSET = 0x100; + + readonly byte[] headerId = {0x44, 0x49, 0x46, 0x43, 0x20, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x20}; + byte[] comment; /// <summary>Disk image file</summary> Filter dimImageFilter; - byte[] comment; - byte[] hdrId; DiskType dskType; - #endregion + byte[] hdrId; public Dim() { @@ -364,7 +348,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -525,6 +508,15 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + enum DiskType : byte + { + Hd2 = 0, + Hs2 = 1, + Hc2 = 2, + Hde2 = 3, + Hq2 = 9, + N88 = 17 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DiscFerret.cs b/DiscImageChef.DiscImages/DiscFerret.cs index e894ac8b1..1c33f4a92 100644 --- a/DiscImageChef.DiscImages/DiscFerret.cs +++ b/DiscImageChef.DiscImages/DiscFerret.cs @@ -42,33 +42,17 @@ namespace DiscImageChef.DiscImages { public class DiscFerret : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct DfiBlockHeader - { - public ushort cylinder; - public ushort head; - public ushort sector; - public uint length; - } - #endregion Internal Structures - - #region Internal Constants /// <summary> - /// "DFER" + /// "DFER" /// </summary> const uint DFI_MAGIC = 0x52454644; /// <summary> - /// "DFE2" + /// "DFE2" /// </summary> const uint DFI_MAGIC2 = 0x32454644; - #endregion Internal Constants - - #region Internal variables // TODO: These variables have been made public so create-sidecar can access to this information until I define an API >4.0 - public SortedDictionary<int, long> TrackOffsets; public SortedDictionary<int, long> TrackLengths; - #endregion Internal variables + public SortedDictionary<int, long> TrackOffsets; public DiscFerret() { @@ -99,7 +83,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { byte[] magicB = new byte[4]; @@ -351,9 +334,7 @@ namespace DiscImageChef.DiscImages { throw new NotImplementedException("Flux decoding is not yet implemented."); } - #endregion Public methods - #region Unsupported features public override byte[] ReadSector(ulong sectorAddress, uint track) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -419,6 +400,14 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DfiBlockHeader + { + public ushort cylinder; + public ushort head; + public ushort sector; + public uint length; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DiscJuggler.cs b/DiscImageChef.DiscImages/DiscJuggler.cs index d94a4f90c..aff0e8ee5 100644 --- a/DiscImageChef.DiscImages/DiscJuggler.cs +++ b/DiscImageChef.DiscImages/DiscJuggler.cs @@ -45,13 +45,13 @@ namespace DiscImageChef.DiscImages // Support separate data files? Never seen a DiscJuggler image using them anyways... public class DiscJuggler : ImagePlugin { - Stream imageStream; - List<Session> sessions; - List<Track> tracks; byte[] cdtext; + Stream imageStream; Dictionary<uint, ulong> offsetmap; List<Partition> partitions; + List<Session> sessions; Dictionary<uint, byte> trackFlags; + List<Track> tracks; public DiscJuggler() { @@ -106,9 +106,7 @@ namespace DiscImageChef.DiscImages descriptor[14] != 0xFF || descriptor[15] != 0xFF) return false; // Too many tracks - if(descriptor[2] > 99) return false; - - return true; + return descriptor[2] <= 99; } public override bool OpenImage(Filter imageFilter) @@ -347,8 +345,7 @@ namespace DiscImageChef.DiscImages track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; currentOffset += trackLen * (ulong)(track.TrackRawBytesPerSector + 96); break; - default: - throw new ImageNotSupportedException($"Unknown read mode {readMode}"); + default: throw new ImageNotSupportedException($"Unknown read mode {readMode}"); } break; @@ -366,8 +363,8 @@ namespace DiscImageChef.DiscImages currentOffset += trackLen * (ulong)track.TrackRawBytesPerSector; break; case 1: - throw new - ImageNotSupportedException($"Invalid read mode {readMode} for this track"); + throw + new ImageNotSupportedException($"Invalid read mode {readMode} for this track"); case 2: track.TrackRawBytesPerSector = 2352; currentOffset += trackLen * (ulong)track.TrackRawBytesPerSector; @@ -426,8 +423,7 @@ namespace DiscImageChef.DiscImages if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc)) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc); break; - default: - throw new ImageNotSupportedException($"Unknown read mode {readMode}"); + default: throw new ImageNotSupportedException($"Unknown read mode {readMode}"); } break; @@ -439,8 +435,8 @@ namespace DiscImageChef.DiscImages switch(readMode) { case 0: - throw new - ImageNotSupportedException($"Invalid read mode {readMode} for this track"); + throw + new ImageNotSupportedException($"Invalid read mode {readMode} for this track"); case 1: track.TrackRawBytesPerSector = 2336; if(firstTrack) currentOffset += 150 * (ulong)track.TrackRawBytesPerSector; @@ -481,13 +477,11 @@ namespace DiscImageChef.DiscImages if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorHeader)) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader); break; - default: - throw new ImageNotSupportedException($"Unknown read mode {readMode}"); + default: throw new ImageNotSupportedException($"Unknown read mode {readMode}"); } break; - default: - throw new ImageNotSupportedException($"Unknown track mode {trackMode}"); + default: throw new ImageNotSupportedException($"Unknown track mode {trackMode}"); } track.TrackFile = imageFilter.GetFilename(); @@ -701,14 +695,24 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress < track.TrackEndSector select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress < track.TrackEndSector + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in offsetmap.Where(kvp => sectorAddress >= kvp.Value).Where(kvp => tracks.Where(track => track.TrackSequence == kvp.Key).Any(track => sectorAddress < track.TrackEndSector))) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in offsetmap + .Where(kvp => sectorAddress >= kvp.Value) + .Where(kvp => tracks.Where(track => track.TrackSequence == kvp.Key) + .Any(track => sectorAddress < track.TrackEndSector))) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -717,7 +721,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -809,8 +814,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -899,9 +904,13 @@ namespace DiscImageChef.DiscImages break; } case SectorTagType.CdSectorSubchannel: - switch(dicTrack.TrackSubchannelType) { - case TrackSubchannelType.None: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); - case TrackSubchannelType.Q16Interleaved: throw new ArgumentException("Q16 subchannel not yet supported"); + switch(dicTrack.TrackSubchannelType) + { + case TrackSubchannelType.None: + throw new ArgumentException("Unsupported tag requested for this track", + nameof(tag)); + case TrackSubchannelType.Q16Interleaved: + throw new ArgumentException("Q16 subchannel not yet supported"); } sectorOffset = 2352; @@ -940,9 +949,13 @@ namespace DiscImageChef.DiscImages break; } case SectorTagType.CdSectorSubchannel: - switch(dicTrack.TrackSubchannelType) { - case TrackSubchannelType.None: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); - case TrackSubchannelType.Q16Interleaved: throw new ArgumentException("Q16 subchannel not yet supported"); + switch(dicTrack.TrackSubchannelType) + { + case TrackSubchannelType.None: + throw new ArgumentException("Unsupported tag requested for this track", + nameof(tag)); + case TrackSubchannelType.Q16Interleaved: + throw new ArgumentException("Q16 subchannel not yet supported"); } sectorOffset = 2352; @@ -959,9 +972,13 @@ namespace DiscImageChef.DiscImages switch(tag) { case SectorTagType.CdSectorSubchannel: - switch(dicTrack.TrackSubchannelType) { - case TrackSubchannelType.None: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); - case TrackSubchannelType.Q16Interleaved: throw new ArgumentException("Q16 subchannel not yet supported"); + switch(dicTrack.TrackSubchannelType) + { + case TrackSubchannelType.None: + throw new ArgumentException("Unsupported tag requested for this track", + nameof(tag)); + case TrackSubchannelType.Q16Interleaved: + throw new ArgumentException("Q16 subchannel not yet supported"); } sectorOffset = 2352; @@ -1020,7 +1037,14 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in tracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -1029,8 +1053,8 @@ namespace DiscImageChef.DiscImages { Track dicTrack = new Track {TrackSequence = 0}; - - foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) { + foreach(Track linqTrack in tracks.Where(linqTrack => linqTrack.TrackSequence == track)) + { dicTrack = linqTrack; break; } @@ -1241,9 +1265,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, @@ -1272,9 +1295,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() diff --git a/DiscImageChef.DiscImages/DiskCopy42.cs b/DiscImageChef.DiscImages/DiskCopy42.cs index 9700a7496..44f075c86 100644 --- a/DiscImageChef.DiscImages/DiskCopy42.cs +++ b/DiscImageChef.DiscImages/DiskCopy42.cs @@ -48,32 +48,6 @@ namespace DiscImageChef.DiscImages [SuppressMessage("ReSharper", "InconsistentNaming")] public class DiskCopy42 : ImagePlugin { - #region Internal Structures - // DiskCopy 4.2 header, big-endian, data-fork, start of file, 84 bytes - struct Dc42Header - { - /// <summary>0x00, 64 bytes, pascal string, disk name or "-not a Macintosh disk-", filled with garbage</summary> - public string DiskName; - /// <summary>0x40, size of data in bytes (usually sectors*512)</summary> - public uint DataSize; - /// <summary>0x44, size of tags in bytes (usually sectors*12)</summary> - public uint TagSize; - /// <summary>0x48, checksum of data bytes</summary> - public uint DataChecksum; - /// <summary>0x4C, checksum of tag bytes</summary> - public uint TagChecksum; - /// <summary>0x50, format of disk, see constants</summary> - public byte Format; - /// <summary>0x51, format of sectors, see constants</summary> - public byte FmtByte; - /// <summary>0x52, is disk image valid? always 0x01</summary> - public byte Valid; - /// <summary>0x53, reserved, always 0x00</summary> - public byte Reserved; - } - #endregion - - #region Internal Constants // format byte /// <summary>3.5", single side, double density, GCR</summary> const byte kSonyFormat400K = 0x00; @@ -104,7 +78,10 @@ namespace DiscImageChef.DiscImages const byte kSonyFmtByte1680K = kSonyFmtByte400K; /// <summary>3.5" double side double density GCR, 512 bytes/sector, interleave 2:1</summary> const byte kSonyFmtByte800K = 0x22; - /// <summary>3.5" double side double density GCR, 512 bytes/sector, interleave 2:1, incorrect value (but appears on official documentation)</summary> + /// <summary> + /// 3.5" double side double density GCR, 512 bytes/sector, interleave 2:1, incorrect value (but appears on + /// official documentation) + /// </summary> const byte kSonyFmtByte800KIncorrect = 0x12; /// <summary>3.5" double side double density GCR, ProDOS format, interleave 4:1</summary> const byte kSonyFmtByteProDos = 0x24; @@ -114,24 +91,20 @@ namespace DiscImageChef.DiscImages const byte kFmtNotStandard = 0x93; /// <summary>Used incorrectly by Mac OS X with certaing disk images</summary> const byte kMacOSXFmtByte = 0x00; - #endregion - - #region Internal variables - /// <summary>Start of data sectors in disk image, should be 0x58</summary> - uint dataOffset; - /// <summary>Start of tags in disk image, after data sectors</summary> - uint tagOffset; /// <summary>Bytes per tag, should be 12</summary> uint bptag; - /// <summary>Header of opened image</summary> - Dc42Header header; + + /// <summary>Start of data sectors in disk image, should be 0x58</summary> + uint dataOffset; /// <summary>Disk image file</summary> Filter dc42ImageFilter; - + /// <summary>Header of opened image</summary> + Dc42Header header; + /// <summary>Start of tags in disk image, after data sectors</summary> + uint tagOffset; + bool twiggy; byte[] twiggyCache; byte[] twiggyCacheTags; - bool twiggy; - #endregion public DiskCopy42() { @@ -474,8 +447,7 @@ namespace DiscImageChef.DiscImages string major = $"{version.MajorVersion}"; string minor = $".{version.MinorVersion / 10}"; - if(version.MinorVersion % 10 > 0) - release = $".{version.MinorVersion % 10}"; + if(version.MinorVersion % 10 > 0) release = $".{version.MinorVersion % 10}"; switch(version.DevStage) { case Version.DevelopmentStage.Alpha: @@ -803,7 +775,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -923,9 +894,7 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features - #region Private methods static uint DC42CheckSum(byte[] buffer) { uint dc42Chk = 0; @@ -940,6 +909,28 @@ namespace DiscImageChef.DiscImages return dc42Chk; } - #endregion + + // DiskCopy 4.2 header, big-endian, data-fork, start of file, 84 bytes + struct Dc42Header + { + /// <summary>0x00, 64 bytes, pascal string, disk name or "-not a Macintosh disk-", filled with garbage</summary> + public string DiskName; + /// <summary>0x40, size of data in bytes (usually sectors*512)</summary> + public uint DataSize; + /// <summary>0x44, size of tags in bytes (usually sectors*12)</summary> + public uint TagSize; + /// <summary>0x48, checksum of data bytes</summary> + public uint DataChecksum; + /// <summary>0x4C, checksum of tag bytes</summary> + public uint TagChecksum; + /// <summary>0x50, format of disk, see constants</summary> + public byte Format; + /// <summary>0x51, format of sectors, see constants</summary> + public byte FmtByte; + /// <summary>0x52, is disk image valid? always 0x01</summary> + public byte Valid; + /// <summary>0x53, reserved, always 0x00</summary> + public byte Reserved; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/DriDiskCopy.cs b/DiscImageChef.DiscImages/DriDiskCopy.cs index 8ee0202e2..5aaa86b00 100644 --- a/DiscImageChef.DiscImages/DriDiskCopy.cs +++ b/DiscImageChef.DiscImages/DriDiskCopy.cs @@ -44,94 +44,13 @@ namespace DiscImageChef.DiscImages { public class DriDiskCopy : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct DriFooter - { - /// <summary>Signature: "DiskImage 2.01 (C) 1990,1991 Digital Research Inc\0"</summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 51)] public byte[] signature; - /// <summary>Information about the disk image, mostly imitates FAT BPB</summary> - public DriBpb bpb; - /// <summary>Information about the disk image, mostly imitates FAT BPB, copy</summary> - public DriBpb bpbcopy; - } + const string REGEX_DRI = "DiskImage\\s(?<version>\\d+.\\d+)\\s\\(C\\)\\s\\d+\\,*\\d*\\s+Digital Research Inc"; - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct DriBpb - { - /// <summary>Seems to be always 0x05</summary> - public byte five; - /// <summary>A drive code that corresponds (but it not equal to) CMOS drive types</summary> - public DriDriveCodes driveCode; - /// <summary>Unknown seems to be always 2</summary> - public ushort unknown; - /// <summary>Cylinders</summary> - public ushort cylinders; - /// <summary>Seems to always be 0</summary> - public byte unknown2; - /// <summary>Bytes per sector</summary> - public ushort bps; - /// <summary>Sectors per cluster</summary> - public byte spc; - /// <summary>Sectors between BPB and FAT</summary> - public ushort rsectors; - /// <summary>How many FATs</summary> - public byte fats_no; - /// <summary>Entries in root directory</summary> - public ushort root_entries; - /// <summary>Total sectors</summary> - public ushort sectors; - /// <summary>Media descriptor</summary> - public byte media_descriptor; - /// <summary>Sectors per FAT</summary> - public ushort spfat; - /// <summary>Sectors per track</summary> - public ushort sptrack; - /// <summary>Heads</summary> - public ushort heads; - /// <summary>Hidden sectors before BPB</summary> - public uint hsectors; - /// <summary>Drive number</summary> - public byte drive_no; - /// <summary>Seems to be 0</summary> - public ulong unknown3; - /// <summary>Seems to be 0</summary> - public byte unknown4; - /// <summary>Sectors per track (again?)</summary> - public ushort sptrack2; - /// <summary>Seems to be 0</summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 144)] public byte[] unknown5; - } - #endregion - - #region Internal Constants - /// <summary> - /// Drive codes change according to CMOS stored valued - /// </summary> - [SuppressMessage("ReSharper", "InconsistentNaming")] - enum DriDriveCodes : byte - { - /// <summary>5.25" 360k</summary> - md2dd = 0, - /// <summary>5.25" 1.2M</summary> - md2hd = 1, - /// <summary>3.5" 720k</summary> - mf2dd = 2, - /// <summary>3.5" 1.44M</summary> - mf2hd = 7, - /// <summary>3.5" 2.88M</summary> - mf2ed = 9 - } - - const string DRI_REG_EX = "DiskImage\\s(?<version>\\d+.\\d+)\\s\\(C\\)\\s\\d+\\,*\\d*\\s+Digital Research Inc"; - #endregion - - #region Internal variables - /// <summary>Footer of opened image</summary> - DriFooter footer; /// <summary>Disk image file</summary> Filter driImageFilter; - #endregion + + /// <summary>Footer of opened image</summary> + DriFooter footer; public DriDiskCopy() { @@ -179,11 +98,9 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.signature = \"{0}\"", sig); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.five = {0}", tmpFooter.bpb.five); - DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.driveCode = {0}", - tmpFooter.bpb.driveCode); + DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.driveCode = {0}", tmpFooter.bpb.driveCode); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.unknown = {0}", tmpFooter.bpb.unknown); - DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.cylinders = {0}", - tmpFooter.bpb.cylinders); + DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.cylinders = {0}", tmpFooter.bpb.cylinders); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.unknown2 = {0}", tmpFooter.bpb.unknown2); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.bps = {0}", tmpFooter.bpb.bps); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "tmp_footer.bpb.spc = {0}", tmpFooter.bpb.spc); @@ -204,20 +121,17 @@ namespace DiscImageChef.DiscImages "ArrayHelpers.ArrayIsNullOrEmpty(tmp_footer.bpb.unknown5) = {0}", ArrayHelpers.ArrayIsNullOrEmpty(tmpFooter.bpb.unknown5)); - Regex regexSignature = new Regex(DRI_REG_EX); + Regex regexSignature = new Regex(REGEX_DRI); Match matchSignature = regexSignature.Match(sig); DicConsole.DebugWriteLine("DRI DiskCopy plugin", "MatchSignature.Success? = {0}", matchSignature.Success); if(!matchSignature.Success) return false; - if(tmpFooter.bpb.sptrack * tmpFooter.bpb.cylinders * tmpFooter.bpb.heads != - tmpFooter.bpb.sectors) return false; - - if(tmpFooter.bpb.sectors * tmpFooter.bpb.bps + Marshal.SizeOf(tmpFooter) != stream.Length) + if(tmpFooter.bpb.sptrack * tmpFooter.bpb.cylinders * tmpFooter.bpb.heads != tmpFooter.bpb.sectors) return false; - return true; + return tmpFooter.bpb.sectors * tmpFooter.bpb.bps + Marshal.SizeOf(tmpFooter) == stream.Length; } public override bool OpenImage(Filter imageFilter) @@ -238,7 +152,7 @@ namespace DiscImageChef.DiscImages string sig = StringHandlers.CToString(footer.signature); - Regex regexSignature = new Regex(DRI_REG_EX); + Regex regexSignature = new Regex(REGEX_DRI); Match matchSignature = regexSignature.Match(sig); if(!matchSignature.Success) return false; @@ -488,7 +402,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -608,6 +521,81 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DriFooter + { + /// <summary>Signature: "DiskImage 2.01 (C) 1990,1991 Digital Research Inc\0"</summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 51)] public byte[] signature; + /// <summary>Information about the disk image, mostly imitates FAT BPB</summary> + public DriBpb bpb; + /// <summary>Information about the disk image, mostly imitates FAT BPB, copy</summary> + public DriBpb bpbcopy; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct DriBpb + { + /// <summary>Seems to be always 0x05</summary> + public byte five; + /// <summary>A drive code that corresponds (but it not equal to) CMOS drive types</summary> + public DriDriveCodes driveCode; + /// <summary>Unknown seems to be always 2</summary> + public ushort unknown; + /// <summary>Cylinders</summary> + public ushort cylinders; + /// <summary>Seems to always be 0</summary> + public byte unknown2; + /// <summary>Bytes per sector</summary> + public ushort bps; + /// <summary>Sectors per cluster</summary> + public byte spc; + /// <summary>Sectors between BPB and FAT</summary> + public ushort rsectors; + /// <summary>How many FATs</summary> + public byte fats_no; + /// <summary>Entries in root directory</summary> + public ushort root_entries; + /// <summary>Total sectors</summary> + public ushort sectors; + /// <summary>Media descriptor</summary> + public byte media_descriptor; + /// <summary>Sectors per FAT</summary> + public ushort spfat; + /// <summary>Sectors per track</summary> + public ushort sptrack; + /// <summary>Heads</summary> + public ushort heads; + /// <summary>Hidden sectors before BPB</summary> + public uint hsectors; + /// <summary>Drive number</summary> + public byte drive_no; + /// <summary>Seems to be 0</summary> + public ulong unknown3; + /// <summary>Seems to be 0</summary> + public byte unknown4; + /// <summary>Sectors per track (again?)</summary> + public ushort sptrack2; + /// <summary>Seems to be 0</summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 144)] public byte[] unknown5; + } + + /// <summary> + /// Drive codes change according to CMOS stored valued + /// </summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum DriDriveCodes : byte + { + /// <summary>5.25" 360k</summary> + md2dd = 0, + /// <summary>5.25" 1.2M</summary> + md2hd = 1, + /// <summary>3.5" 720k</summary> + mf2dd = 2, + /// <summary>3.5" 1.44M</summary> + mf2hd = 7, + /// <summary>3.5" 2.88M</summary> + mf2ed = 9 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/GDI.cs b/DiscImageChef.DiscImages/GDI.cs index fc11e10f0..440c40c41 100644 --- a/DiscImageChef.DiscImages/GDI.cs +++ b/DiscImageChef.DiscImages/GDI.cs @@ -46,61 +46,18 @@ namespace DiscImageChef.DiscImages // TODO: This format doesn't support to specify pregaps that are included in the file (like Redump ones) public class Gdi : ImagePlugin { - #region Internal structures - struct GdiTrack - { - /// <summary>Track #</summary> - public uint Sequence; - /// <summary>Track filter</summary> - public Filter Trackfilter; - /// <summary>Track file</summary> - public string Trackfile; - /// <summary>Track byte offset in file</summary> - public long Offset; - /// <summary>Track flags</summary> - public byte Flags; - /// <summary>Track starting sector</summary> - public ulong StartSector; - /// <summary>Bytes per sector</summary> - public ushort Bps; - /// <summary>Sectors in track</summary> - public ulong Sectors; - /// <summary>Track type</summary> - public TrackType Tracktype; - /// <summary>Track session</summary> - public bool HighDensity; - /// <summary>Pregap sectors not stored in track file</summary> - public ulong Pregap; - } + const string REGEX_TRACK = + "\\s?(?<track>\\d+)\\s+(?<start>\\d+)\\s(?<flags>\\d)\\s(?<type>2352|2048)\\s(?<filename>.+)\\s(?<offset>\\d+)$" + ; - struct GdiDisc - { - /// <summary>Sessions</summary> - public List<Session> Sessions; - /// <summary>Tracks</summary> - public List<GdiTrack> Tracks; - /// <summary>Disk type</summary> - public MediaType Disktype; - } - #endregion Internal structures - - #region Internal variables + ulong densitySeparationSectors; + GdiDisc discimage; StreamReader gdiStream; Stream imageStream; /// <summary>Dictionary, index is track #, value is track number, or 0 if a TOC</summary> Dictionary<uint, ulong> offsetmap; - GdiDisc discimage; List<Partition> partitions; - ulong densitySeparationSectors; - #endregion Internal variables - #region Parsing regexs - const string TRACK_REGEX = - "\\s?(?<track>\\d+)\\s+(?<start>\\d+)\\s(?<flags>\\d)\\s(?<type>2352|2048)\\s(?<filename>.+)\\s(?<offset>\\d+)$" - ; - #endregion Parsing regexs - - #region Public methods public Gdi() { Name = "Dreamcast GDI image"; @@ -167,7 +124,7 @@ namespace DiscImageChef.DiscImages if(lineNumber == 1) { if(!int.TryParse(line, out tracks)) return false; } else { - Regex regexTrack = new Regex(TRACK_REGEX); + Regex regexTrack = new Regex(REGEX_TRACK); Match trackMatch = regexTrack.Match(line ?? throw new InvalidOperationException()); @@ -202,7 +159,7 @@ namespace DiscImageChef.DiscImages bool highDensity = false; // Initialize all RegExs - Regex regexTrack = new Regex(TRACK_REGEX); + Regex regexTrack = new Regex(REGEX_TRACK); // Initialize all RegEx matches @@ -266,8 +223,8 @@ namespace DiscImageChef.DiscImages currentTrack.StartSector -= currentTrack.StartSector - currentStart; } - if((currentTrack.Trackfilter.GetDataForkLength() - currentTrack.Offset) % currentTrack.Bps != - 0) throw new ImageNotSupportedException("Track size not a multiple of sector size"); + if((currentTrack.Trackfilter.GetDataForkLength() - currentTrack.Offset) % currentTrack.Bps != 0) + throw new ImageNotSupportedException("Track size not a multiple of sector size"); currentTrack.Sectors = (ulong)((currentTrack.Trackfilter.GetDataForkLength() - currentTrack.Offset) / @@ -276,7 +233,8 @@ namespace DiscImageChef.DiscImages currentStart += currentTrack.Sectors; currentTrack.HighDensity = highDensity; - currentTrack.Tracktype = (currentTrack.Flags & 0x40) == 0x40 ? TrackType.CdMode1 : TrackType.Audio; + currentTrack.Tracktype = + (currentTrack.Flags & 0x40) == 0x40 ? TrackType.CdMode1 : TrackType.Audio; discimage.Tracks.Add(currentTrack); } @@ -288,14 +246,14 @@ namespace DiscImageChef.DiscImages { sessions[s].SessionSequence = 1; - foreach(GdiTrack trk in discimage.Tracks.Where(trk => !trk.HighDensity)) { + foreach(GdiTrack trk in discimage.Tracks.Where(trk => !trk.HighDensity)) + { if(sessions[s].StartTrack == 0) sessions[s].StartTrack = trk.Sequence; else if(sessions[s].StartTrack > trk.Sequence) sessions[s].StartTrack = trk.Sequence; if(sessions[s].EndTrack < trk.Sequence) sessions[s].EndTrack = trk.Sequence; - if(sessions[s].StartSector > trk.StartSector) - sessions[s].StartSector = trk.StartSector; + if(sessions[s].StartSector > trk.StartSector) sessions[s].StartSector = trk.StartSector; if(sessions[s].EndSector < trk.Sectors + trk.StartSector - 1) sessions[s].EndSector = trk.Sectors + trk.StartSector - 1; @@ -305,14 +263,14 @@ namespace DiscImageChef.DiscImages { sessions[s].SessionSequence = 2; - foreach(GdiTrack trk in discimage.Tracks.Where(trk => trk.HighDensity)) { + foreach(GdiTrack trk in discimage.Tracks.Where(trk => trk.HighDensity)) + { if(sessions[s].StartTrack == 0) sessions[s].StartTrack = trk.Sequence; else if(sessions[s].StartTrack > trk.Sequence) sessions[s].StartTrack = trk.Sequence; if(sessions[s].EndTrack < trk.Sequence) sessions[s].EndTrack = trk.Sequence; - if(sessions[s].StartSector > trk.StartSector) - sessions[s].StartSector = trk.StartSector; + if(sessions[s].StartSector > trk.StartSector) sessions[s].StartSector = trk.StartSector; if(sessions[s].EndSector < trk.Sectors + trk.StartSector - 1) sessions[s].EndSector = trk.Sectors + trk.StartSector - 1; @@ -398,7 +356,9 @@ namespace DiscImageChef.DiscImages ImageInfo.SectorSize = 2352; // All others - foreach(GdiTrack track in discimage.Tracks.Where(track => (track.Flags & 0x40) == 0x40 && track.Bps == 2352)) { + foreach(GdiTrack unused in + discimage.Tracks.Where(track => (track.Flags & 0x40) == 0x40 && track.Bps == 2352)) + { ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSync); ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorHeader); ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubHeader); @@ -477,7 +437,13 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from gdiTrack in discimage.Tracks where gdiTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < gdiTrack.Sectors select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from gdiTrack in discimage.Tracks + where gdiTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < gdiTrack.Sectors + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); offsetmap.TryGetValue(0, out ulong transitionStart); if(sectorAddress >= transitionStart && sectorAddress < densitySeparationSectors + transitionStart) @@ -488,7 +454,13 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from gdiTrack in discimage.Tracks where gdiTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < gdiTrack.Sectors select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from gdiTrack in discimage.Tracks + where gdiTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < gdiTrack.Sectors + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); offsetmap.TryGetValue(0, out ulong transitionStart); if(sectorAddress >= transitionStart && sectorAddress < densitySeparationSectors + transitionStart) @@ -510,7 +482,8 @@ namespace DiscImageChef.DiscImages GdiTrack dicTrack = new GdiTrack {Sequence = 0}; - foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { + foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) + { dicTrack = gdiTrack; break; } @@ -611,7 +584,8 @@ namespace DiscImageChef.DiscImages GdiTrack dicTrack = new GdiTrack {Sequence = 0}; - foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { + foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) + { dicTrack = gdiTrack; break; } @@ -763,7 +737,13 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from gdiTrack in discimage.Tracks where gdiTrack.Sequence == kvp.Key where sectorAddress - kvp.Value < gdiTrack.Sectors select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from gdiTrack in discimage.Tracks + where gdiTrack.Sequence == kvp.Key + where sectorAddress - kvp.Value < gdiTrack.Sectors + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } @@ -781,7 +761,8 @@ namespace DiscImageChef.DiscImages GdiTrack dicTrack = new GdiTrack {Sequence = 0}; - foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) { + foreach(GdiTrack gdiTrack in discimage.Tracks.Where(gdiTrack => gdiTrack.Sequence == track)) + { dicTrack = gdiTrack; break; } @@ -1049,9 +1030,8 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas, @@ -1080,18 +1060,15 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion Public methods - #region Unsupported features public override int GetMediaSequence() { return ImageInfo.MediaSequence; @@ -1141,6 +1118,41 @@ namespace DiscImageChef.DiscImages { return ImageInfo.ImageCreator; } - #endregion Unsupported features + + struct GdiTrack + { + /// <summary>Track #</summary> + public uint Sequence; + /// <summary>Track filter</summary> + public Filter Trackfilter; + /// <summary>Track file</summary> + public string Trackfile; + /// <summary>Track byte offset in file</summary> + public long Offset; + /// <summary>Track flags</summary> + public byte Flags; + /// <summary>Track starting sector</summary> + public ulong StartSector; + /// <summary>Bytes per sector</summary> + public ushort Bps; + /// <summary>Sectors in track</summary> + public ulong Sectors; + /// <summary>Track type</summary> + public TrackType Tracktype; + /// <summary>Track session</summary> + public bool HighDensity; + /// <summary>Pregap sectors not stored in track file</summary> + public ulong Pregap; + } + + struct GdiDisc + { + /// <summary>Sessions</summary> + public List<Session> Sessions; + /// <summary>Tracks</summary> + public List<GdiTrack> Tracks; + /// <summary>Disk type</summary> + public MediaType Disktype; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/HDCopy.cs b/DiscImageChef.DiscImages/HDCopy.cs index 528978ce5..868034627 100644 --- a/DiscImageChef.DiscImages/HDCopy.cs +++ b/DiscImageChef.DiscImages/HDCopy.cs @@ -76,87 +76,6 @@ namespace DiscImageChef.DiscImages { public class HdCopy : ImagePlugin { - #region Internal structures - /// <summary> - /// The global header of a HDCP image file - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct HdcpFileHeader - { - /// <summary> - /// Last cylinder (zero-based) - /// </summary> - public byte lastCylinder; - - /// <summary> - /// Sectors per track - /// </summary> - public byte sectorsPerTrack; - - /// <summary> - /// The track map. It contains one byte for each track. - /// Up to 82 tracks (41 tracks * 2 sides) are supported. - /// 0 means track is not present, 1 means it is present. - /// The first 2 tracks are always present. - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * 82)] public byte[] trackMap; - } - - /// <summary> - /// The header for a RLE-compressed block - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct HdcpBlockHeader - { - /// <summary> - /// The length of the compressed block, in bytes. Little-endian. - /// </summary> - public ushort length; - - /// <summary> - /// The byte value used as RLE escape sequence - /// </summary> - public byte escape; - } - - struct MediaTypeTableEntry - { - public byte Tracks; - public byte SectorsPerTrack; - public MediaType MediaType; - - public MediaTypeTableEntry(byte tracks, byte sectorsPerTrack, MediaType mediaType) - { - Tracks = tracks; - SectorsPerTrack = sectorsPerTrack; - MediaType = mediaType; - } - } - #endregion - - #region Internal variables - /// <summary> - /// The HDCP file header after the image has been opened - /// </summary> - HdcpFileHeader fileHeader; - - /// <summary> - /// Every track that has been read is cached here - /// </summary> - Dictionary<int, byte[]> trackCache = new Dictionary<int, byte[]>(); - - /// <summary> - /// The offset in the file where each track starts, or -1 if the track is not present - /// </summary> - Dictionary<int, long> trackOffset = new Dictionary<int, long>(); - - /// <summary> - /// The ImageFilter we're reading from, after the file has been opened - /// </summary> - Filter hdcpImageFilter; - #endregion - - #region Internal constants readonly MediaTypeTableEntry[] mediaTypes = { new MediaTypeTableEntry(80, 8, MediaType.DOS_35_DS_DD_8), @@ -166,7 +85,26 @@ namespace DiscImageChef.DiscImages new MediaTypeTableEntry(40, 9, MediaType.DOS_525_DS_DD_9), new MediaTypeTableEntry(80, 15, MediaType.DOS_525_HD) }; - #endregion + + /// <summary> + /// The HDCP file header after the image has been opened + /// </summary> + HdcpFileHeader fileHeader; + + /// <summary> + /// The ImageFilter we're reading from, after the file has been opened + /// </summary> + Filter hdcpImageFilter; + + /// <summary> + /// Every track that has been read is cached here + /// </summary> + Dictionary<int, byte[]> trackCache = new Dictionary<int, byte[]>(); + + /// <summary> + /// The offset in the file where each track starts, or -1 if the track is not present + /// </summary> + Dictionary<int, long> trackOffset = new Dictionary<int, long>(); public HdCopy() { @@ -367,7 +305,9 @@ namespace DiscImageChef.DiscImages public override MediaType GetMediaType() { - return (from ent in mediaTypes where ent.Tracks == ImageInfo.Cylinders && ent.SectorsPerTrack == ImageInfo.SectorsPerTrack select ent.MediaType).FirstOrDefault(); + return (from ent in mediaTypes + where ent.Tracks == ImageInfo.Cylinders && ent.SectorsPerTrack == ImageInfo.SectorsPerTrack + select ent.MediaType).FirstOrDefault(); } void ReadTrackIntoCache(Stream stream, int tracknum) @@ -444,12 +384,12 @@ namespace DiscImageChef.DiscImages if(sectorAddress + length > ImageInfo.Sectors) throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than available"); - for(int i = 0; i < length; i++) ReadSector(sectorAddress + (ulong)i).CopyTo(result, i * ImageInfo.SectorSize); + for(int i = 0; i < length; i++) + ReadSector(sectorAddress + (ulong)i).CopyTo(result, i * ImageInfo.SectorSize); return result; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -610,6 +550,62 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// The global header of a HDCP image file + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HdcpFileHeader + { + /// <summary> + /// Last cylinder (zero-based) + /// </summary> + public byte lastCylinder; + + /// <summary> + /// Sectors per track + /// </summary> + public byte sectorsPerTrack; + + /// <summary> + /// The track map. It contains one byte for each track. + /// Up to 82 tracks (41 tracks * 2 sides) are supported. + /// 0 means track is not present, 1 means it is present. + /// The first 2 tracks are always present. + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * 82)] public byte[] trackMap; + } + + /// <summary> + /// The header for a RLE-compressed block + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HdcpBlockHeader + { + /// <summary> + /// The length of the compressed block, in bytes. Little-endian. + /// </summary> + public ushort length; + + /// <summary> + /// The byte value used as RLE escape sequence + /// </summary> + public byte escape; + } + + // TODO: Structs don't need constructors + struct MediaTypeTableEntry + { + public byte Tracks; + public byte SectorsPerTrack; + public MediaType MediaType; + + public MediaTypeTableEntry(byte tracks, byte sectorsPerTrack, MediaType mediaType) + { + Tracks = tracks; + SectorsPerTrack = sectorsPerTrack; + MediaType = mediaType; + } + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/IMD.cs b/DiscImageChef.DiscImages/IMD.cs index b485991f1..5ae719a4a 100644 --- a/DiscImageChef.DiscImages/IMD.cs +++ b/DiscImageChef.DiscImages/IMD.cs @@ -43,49 +43,14 @@ namespace DiscImageChef.DiscImages { public class Imd : ImagePlugin { - #region Internal enumerations - enum TransferRate : byte - { - /// <summary>500 kbps in FM mode</summary> - FiveHundred = 0, - /// <summary>300 kbps in FM mode</summary> - ThreeHundred = 1, - /// <summary>250 kbps in FM mode</summary> - TwoHundred = 2, - /// <summary>500 kbps in MFM mode</summary> - FiveHundredMfm = 3, - /// <summary>300 kbps in MFM mode</summary> - ThreeHundredMfm = 4, - /// <summary>250 kbps in MFM mode</summary> - TwoHundredMfm = 5 - } - - enum SectorType : byte - { - Unavailable = 0, - Normal = 1, - Compressed = 2, - Deleted = 3, - CompressedDeleted = 4, - Error = 5, - CompressedError = 6, - DeletedError = 7, - CompressedDeletedError = 8 - } - #endregion Internal enumerations - - #region Internal Constants const byte SECTOR_CYLINDER_MAP_MASK = 0x80; const byte SECTOR_HEAD_MAP_MASK = 0x40; const byte COMMENT_END = 0x1A; - const string HEADER_REGEX = + const string REGEX_HEADER = "IMD (?<version>\\d.\\d+):\\s+(?<day>\\d+)\\/\\s*(?<month>\\d+)\\/(?<year>\\d+)\\s+(?<hour>\\d+):(?<minute>\\d+):(?<second>\\d+)\\r\\n" ; - #endregion Internal Constants - #region Internal variables List<byte[]> sectorsData; - #endregion Internal variables public Imd() { @@ -116,7 +81,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -126,7 +90,7 @@ namespace DiscImageChef.DiscImages byte[] hdr = new byte[31]; stream.Read(hdr, 0, 31); - Regex hr = new Regex(HEADER_REGEX); + Regex hr = new Regex(REGEX_HEADER); Match hm = hr.Match(Encoding.ASCII.GetString(hdr)); return hm.Success; @@ -221,8 +185,7 @@ namespace DiscImageChef.DiscImages ArrayHelpers.ArrayFill(data, filling); if(!track.ContainsKey(idmap[i])) track.Add(idmap[i], data); break; - default: - throw new ImageNotSupportedException($"Invalid sector type {(byte)type}"); + default: throw new ImageNotSupportedException($"Invalid sector type {(byte)type}"); } } @@ -523,9 +486,7 @@ namespace DiscImageChef.DiscImages { return ImageInfo.DriveSerialNumber; } - #endregion Public methods - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -605,6 +566,34 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + enum TransferRate : byte + { + /// <summary>500 kbps in FM mode</summary> + FiveHundred = 0, + /// <summary>300 kbps in FM mode</summary> + ThreeHundred = 1, + /// <summary>250 kbps in FM mode</summary> + TwoHundred = 2, + /// <summary>500 kbps in MFM mode</summary> + FiveHundredMfm = 3, + /// <summary>300 kbps in MFM mode</summary> + ThreeHundredMfm = 4, + /// <summary>250 kbps in MFM mode</summary> + TwoHundredMfm = 5 + } + + enum SectorType : byte + { + Unavailable = 0, + Normal = 1, + Compressed = 2, + Deleted = 3, + CompressedDeleted = 4, + Error = 5, + CompressedError = 6, + DeletedError = 7, + CompressedDeletedError = 8 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/ImagePlugin.cs b/DiscImageChef.DiscImages/ImagePlugin.cs index b227ce9f8..01c82ad28 100644 --- a/DiscImageChef.DiscImages/ImagePlugin.cs +++ b/DiscImageChef.DiscImages/ImagePlugin.cs @@ -39,35 +39,45 @@ using DiscImageChef.Filters; namespace DiscImageChef.DiscImages { /// <summary> - /// Abstract class to implement disk image reading plugins. + /// Abstract class to implement disk image reading plugins. /// </summary> public abstract class ImagePlugin { + // CD flags bitmask + + /// <summary>Track is quadraphonic.</summary> + public const byte CdFlagsFourChannel = 0x20; + /// <summary>Track is non-audio (data).</summary> + public const byte CdFlagsDataTrack = 0x10; + /// <summary>Track is copy protected.</summary> + public const byte CdFlagsCopyPrevent = 0x08; + /// <summary>Track has pre-emphasis.</summary> + public const byte CdFlagsPreEmphasis = 0x04; + /// <summary>Image information</summary> + public ImageInfo ImageInfo; /// <summary>Plugin name.</summary> public string Name; /// <summary>Plugin UUID.</summary> public Guid PluginUuid; - /// <summary>Image information</summary> - public ImageInfo ImageInfo; // Basic image handling functions /// <summary> - /// Identifies the image. + /// Identifies the image. /// </summary> /// <returns><c>true</c>, if image was identified, <c>false</c> otherwise.</returns> /// <param name="imageFilter">Image filter.</param> public abstract bool IdentifyImage(Filter imageFilter); /// <summary> - /// Opens the image. + /// Opens the image. /// </summary> /// <returns><c>true</c>, if image was opened, <c>false</c> otherwise.</returns> /// <param name="imageFilter">Image filter.</param> public abstract bool OpenImage(Filter imageFilter); /// <summary> - /// Asks the disk image plugin if the image contains partitions + /// Asks the disk image plugin if the image contains partitions /// </summary> /// <returns><c>true</c>, if the image contains partitions, <c>false</c> otherwise.</returns> public abstract bool ImageHasPartitions(); @@ -75,19 +85,19 @@ namespace DiscImageChef.DiscImages // Image size functions /// <summary> - /// Gets the size of the image, without headers. + /// Gets the size of the image, without headers. /// </summary> /// <returns>The image size.</returns> public abstract ulong GetImageSize(); /// <summary> - /// Gets the number of sectors in the image. + /// Gets the number of sectors in the image. /// </summary> /// <returns>Sectors in image.</returns> public abstract ulong GetSectors(); /// <summary> - /// Returns the size of the biggest sector, counting user data only. + /// Returns the size of the biggest sector, counting user data only. /// </summary> /// <returns>Biggest sector size (user data only).</returns> public abstract uint GetSectorSize(); @@ -95,21 +105,21 @@ namespace DiscImageChef.DiscImages // Image reading functions /// <summary> - /// Reads a disk tag. + /// Reads a disk tag. /// </summary> /// <returns>Disk tag</returns> /// <param name="tag">Tag type to read.</param> public abstract byte[] ReadDiskTag(MediaTagType tag); /// <summary> - /// Reads a sector's user data. + /// Reads a sector's user data. /// </summary> /// <returns>The sector's user data.</returns> /// <param name="sectorAddress">Sector address (LBA).</param> public abstract byte[] ReadSector(ulong sectorAddress); /// <summary> - /// Reads a sector's tag. + /// Reads a sector's tag. /// </summary> /// <returns>The sector's tag.</returns> /// <param name="sectorAddress">Sector address (LBA).</param> @@ -117,7 +127,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag); /// <summary> - /// Reads a sector's user data, relative to track. + /// Reads a sector's user data, relative to track. /// </summary> /// <returns>The sector's user data.</returns> /// <param name="sectorAddress">Sector address (relative LBA).</param> @@ -125,7 +135,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSector(ulong sectorAddress, uint track); /// <summary> - /// Reads a sector's tag, relative to track. + /// Reads a sector's tag, relative to track. /// </summary> /// <returns>The sector's tag.</returns> /// <param name="sectorAddress">Sector address (relative LBA).</param> @@ -134,7 +144,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag); /// <summary> - /// Reads user data from several sectors. + /// Reads user data from several sectors. /// </summary> /// <returns>The sectors user data.</returns> /// <param name="sectorAddress">Starting sector address (LBA).</param> @@ -142,7 +152,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectors(ulong sectorAddress, uint length); /// <summary> - /// Reads tag from several sectors. + /// Reads tag from several sectors. /// </summary> /// <returns>The sectors tag.</returns> /// <param name="sectorAddress">Starting sector address (LBA).</param> @@ -151,7 +161,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag); /// <summary> - /// Reads user data from several sectors, relative to track. + /// Reads user data from several sectors, relative to track. /// </summary> /// <returns>The sectors user data.</returns> /// <param name="sectorAddress">Starting sector address (relative LBA).</param> @@ -160,7 +170,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectors(ulong sectorAddress, uint length, uint track); /// <summary> - /// Reads tag from several sectors, relative to track. + /// Reads tag from several sectors, relative to track. /// </summary> /// <returns>The sectors tag.</returns> /// <param name="sectorAddress">Starting sector address (relative LBA).</param> @@ -170,14 +180,14 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag); /// <summary> - /// Reads a complete sector (user data + all tags). + /// Reads a complete sector (user data + all tags). /// </summary> /// <returns>The complete sector. Format depends on disk type.</returns> /// <param name="sectorAddress">Sector address (LBA).</param> public abstract byte[] ReadSectorLong(ulong sectorAddress); /// <summary> - /// Reads a complete sector (user data + all tags), relative to track. + /// Reads a complete sector (user data + all tags), relative to track. /// </summary> /// <returns>The complete sector. Format depends on disk type.</returns> /// <param name="sectorAddress">Sector address (relative LBA).</param> @@ -185,7 +195,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorLong(ulong sectorAddress, uint track); /// <summary> - /// Reads several complete sector (user data + all tags). + /// Reads several complete sector (user data + all tags). /// </summary> /// <returns>The complete sectors. Format depends on disk type.</returns> /// <param name="sectorAddress">Starting sector address (LBA).</param> @@ -193,7 +203,7 @@ namespace DiscImageChef.DiscImages public abstract byte[] ReadSectorsLong(ulong sectorAddress, uint length); /// <summary> - /// Reads several complete sector (user data + all tags), relative to track. + /// Reads several complete sector (user data + all tags), relative to track. /// </summary> /// <returns>The complete sectors. Format depends on disk type.</returns> /// <param name="sectorAddress">Starting sector address (relative LBA).</param> @@ -204,55 +214,55 @@ namespace DiscImageChef.DiscImages // Image information functions /// <summary> - /// Gets the image format. + /// Gets the image format. /// </summary> /// <returns>The image format.</returns> public abstract string GetImageFormat(); /// <summary> - /// Gets the image version. + /// Gets the image version. /// </summary> /// <returns>The image version.</returns> public abstract string GetImageVersion(); /// <summary> - /// Gets the application that created the image. + /// Gets the application that created the image. /// </summary> /// <returns>The application that created the image.</returns> public abstract string GetImageApplication(); /// <summary> - /// Gets the version of the application that created the image. + /// Gets the version of the application that created the image. /// </summary> /// <returns>The version of the application that created the image.</returns> public abstract string GetImageApplicationVersion(); /// <summary> - /// Gets the image creator. + /// Gets the image creator. /// </summary> /// <returns>Who created the image.</returns> public abstract string GetImageCreator(); /// <summary> - /// Gets the image creation time. + /// Gets the image creation time. /// </summary> /// <returns>The image creation time.</returns> public abstract DateTime GetImageCreationTime(); /// <summary> - /// Gets the image last modification time. + /// Gets the image last modification time. /// </summary> /// <returns>The image last modification time.</returns> public abstract DateTime GetImageLastModificationTime(); /// <summary> - /// Gets the name of the image. + /// Gets the name of the image. /// </summary> /// <returns>The image name.</returns> public abstract string GetImageName(); /// <summary> - /// Gets the image comments. + /// Gets the image comments. /// </summary> /// <returns>The image comments.</returns> public abstract string GetImageComments(); @@ -260,49 +270,49 @@ namespace DiscImageChef.DiscImages // Functions to get information from disk represented by image /// <summary> - /// Gets the media manufacturer. + /// Gets the media manufacturer. /// </summary> /// <returns>The media manufacturer.</returns> public abstract string GetMediaManufacturer(); /// <summary> - /// Gets the media model. + /// Gets the media model. /// </summary> /// <returns>The media model.</returns> public abstract string GetMediaModel(); /// <summary> - /// Gets the media serial number. + /// Gets the media serial number. /// </summary> /// <returns>The media serial number.</returns> public abstract string GetMediaSerialNumber(); /// <summary> - /// Gets the media (or product) barcode. + /// Gets the media (or product) barcode. /// </summary> /// <returns>The media barcode.</returns> public abstract string GetMediaBarcode(); /// <summary> - /// Gets the media part number. + /// Gets the media part number. /// </summary> /// <returns>The media part number.</returns> public abstract string GetMediaPartNumber(); /// <summary> - /// Gets the type of the media. + /// Gets the type of the media. /// </summary> /// <returns>The media type.</returns> public abstract MediaType GetMediaType(); /// <summary> - /// Gets the media sequence. + /// Gets the media sequence. /// </summary> /// <returns>The media sequence, starting at 1.</returns> public abstract int GetMediaSequence(); /// <summary> - /// Gets the last media in the sequence. + /// Gets the last media in the sequence. /// </summary> /// <returns>The last media in the sequence.</returns> public abstract int GetLastDiskSequence(); @@ -310,19 +320,19 @@ namespace DiscImageChef.DiscImages // Functions to get information from drive used to create image /// <summary> - /// Gets the manufacturer of the drive used to create the image. + /// Gets the manufacturer of the drive used to create the image. /// </summary> /// <returns>The drive manufacturer.</returns> public abstract string GetDriveManufacturer(); /// <summary> - /// Gets the model of the drive used to create the image. + /// Gets the model of the drive used to create the image. /// </summary> /// <returns>The drive model.</returns> public abstract string GetDriveModel(); /// <summary> - /// Gets the serial number of the drive used to create the image. + /// Gets the serial number of the drive used to create the image. /// </summary> /// <returns>The drive serial number.</returns> public abstract string GetDriveSerialNumber(); @@ -330,48 +340,48 @@ namespace DiscImageChef.DiscImages // Partitioning functions /// <summary> - /// Gets an array partitions. Typically only useful for optical disc - /// images where each track and index means a different partition, as - /// reads can be relative to them. + /// Gets an array partitions. Typically only useful for optical disc + /// images where each track and index means a different partition, as + /// reads can be relative to them. /// </summary> /// <returns>The partitions.</returns> public abstract List<Partition> GetPartitions(); /// <summary> - /// Gets the disc track extents (start, length). + /// Gets the disc track extents (start, length). /// </summary> /// <returns>The track extents.</returns> public abstract List<Track> GetTracks(); /// <summary> - /// Gets the disc track extents for a specified session. + /// Gets the disc track extents for a specified session. /// </summary> /// <returns>The track exents for that session.</returns> /// <param name="session">Session.</param> public abstract List<Track> GetSessionTracks(Session session); /// <summary> - /// Gets the disc track extents for a specified session. + /// Gets the disc track extents for a specified session. /// </summary> /// <returns>The track exents for that session.</returns> /// <param name="session">Session.</param> public abstract List<Track> GetSessionTracks(ushort session); /// <summary> - /// Gets the sessions (optical discs only). + /// Gets the sessions (optical discs only). /// </summary> /// <returns>The sessions.</returns> public abstract List<Session> GetSessions(); /// <summary> - /// Verifies a sector. + /// Verifies a sector. /// </summary> /// <returns>True if correct, false if incorrect, null if uncheckable.</returns> /// <param name="sectorAddress">Sector address (LBA).</param> public abstract bool? VerifySector(ulong sectorAddress); /// <summary> - /// Verifies a sector, relative to track. + /// Verifies a sector, relative to track. /// </summary> /// <returns>True if correct, false if incorrect, null if uncheckable.</returns> /// <param name="sectorAddress">Sector address (relative LBA).</param> @@ -379,7 +389,7 @@ namespace DiscImageChef.DiscImages public abstract bool? VerifySector(ulong sectorAddress, uint track); /// <summary> - /// Verifies several sectors. + /// Verifies several sectors. /// </summary> /// <returns>True if all are correct, false if any is incorrect, null if any is uncheckable.</returns> /// <param name="sectorAddress">Starting sector address (LBA).</param> @@ -390,7 +400,7 @@ namespace DiscImageChef.DiscImages out List<ulong> unknownLbas); /// <summary> - /// Verifies several sectors, relative to track. + /// Verifies several sectors, relative to track. /// </summary> /// <returns>True if all are correct, false if any is incorrect, null if any is uncheckable.</returns> /// <param name="sectorAddress">Starting sector address (relative LBA).</param> @@ -402,25 +412,14 @@ namespace DiscImageChef.DiscImages out List<ulong> unknownLbas); /// <summary> - /// Verifies media image internal checksum. + /// Verifies media image internal checksum. /// </summary> /// <returns>True if correct, false if incorrect, null if there is no internal checksum available</returns> public abstract bool? VerifyMediaImage(); - - // CD flags bitmask - - /// <summary>Track is quadraphonic.</summary> - public const byte CdFlagsFourChannel = 0x20; - /// <summary>Track is non-audio (data).</summary> - public const byte CdFlagsDataTrack = 0x10; - /// <summary>Track is copy protected.</summary> - public const byte CdFlagsCopyPrevent = 0x08; - /// <summary>Track has pre-emphasis.</summary> - public const byte CdFlagsPreEmphasis = 0x04; } /// <summary> - /// Track (as partitioning element) types. + /// Track (as partitioning element) types. /// </summary> public enum TrackType { @@ -439,7 +438,7 @@ namespace DiscImageChef.DiscImages } /// <summary> - /// Track defining structure. + /// Track defining structure. /// </summary> public struct Track { @@ -482,42 +481,42 @@ namespace DiscImageChef.DiscImages } /// <summary> - /// Type of subchannel in track + /// Type of subchannel in track /// </summary> public enum TrackSubchannelType { /// <summary> - /// Track does not has subchannel dumped, or it's not a CD + /// Track does not has subchannel dumped, or it's not a CD /// </summary> None, /// <summary> - /// Subchannel is packed and error corrected + /// Subchannel is packed and error corrected /// </summary> Packed, /// <summary> - /// Subchannel is interleaved + /// Subchannel is interleaved /// </summary> Raw, /// <summary> - /// Subchannel is packed and comes interleaved with main channel in same file + /// Subchannel is packed and comes interleaved with main channel in same file /// </summary> PackedInterleaved, /// <summary> - /// Subchannel is interleaved and comes interleaved with main channel in same file + /// Subchannel is interleaved and comes interleaved with main channel in same file /// </summary> RawInterleaved, /// <summary> - /// Only Q subchannel is stored as 16 bytes + /// Only Q subchannel is stored as 16 bytes /// </summary> Q16, /// <summary> - /// Only Q subchannel is stored as 16 bytes and comes interleaved with main channel in same file + /// Only Q subchannel is stored as 16 bytes and comes interleaved with main channel in same file /// </summary> Q16Interleaved } /// <summary> - /// Session defining structure. + /// Session defining structure. /// </summary> public struct Session { @@ -534,7 +533,7 @@ namespace DiscImageChef.DiscImages } /// <summary> - /// Metadata present for each sector (aka, "tag"). + /// Metadata present for each sector (aka, "tag"). /// </summary> public enum SectorTagType { @@ -569,7 +568,7 @@ namespace DiscImageChef.DiscImages } /// <summary> - /// Metadata present for each media. + /// Metadata present for each media. /// </summary> public enum MediaTagType { @@ -691,41 +690,44 @@ namespace DiscImageChef.DiscImages MMC_ExtendedCSD, /// <summary>Xbox Security Sector</summary> Xbox_SecuritySector, - /// <summary>On floppy disks, data in last cylinder usually in a different format that contains duplication or manufacturing information</summary> + /// <summary> + /// On floppy disks, data in last cylinder usually in a different format that contains duplication or + /// manufacturing information + /// </summary> Floppy_LeadOut } /// <summary> - /// Enumeration of media types defined in CICM metadata + /// Enumeration of media types defined in CICM metadata /// </summary> public enum XmlMediaType { /// <summary> - /// Purely optical discs + /// Purely optical discs /// </summary> OpticalDisc, /// <summary> - /// Media that is physically block-based or abstracted like that + /// Media that is physically block-based or abstracted like that /// </summary> BlockMedia, /// <summary> - /// Media that can be accessed by-byte or by-bit, like chips + /// Media that can be accessed by-byte or by-bit, like chips /// </summary> LinearMedia, /// <summary> - /// Media that can only store data when it is modulated to audio + /// Media that can only store data when it is modulated to audio /// </summary> AudioMedia } /// <summary> - /// Feature is supported by image but not implemented yet. + /// Feature is supported by image but not implemented yet. /// </summary> [Serializable] public class FeatureSupportedButNotImplementedImageException : Exception { /// <summary> - /// Feature is supported by image but not implemented yet. + /// Feature is supported by image but not implemented yet. /// </summary> /// <param name="message">Message.</param> /// <param name="inner">Inner.</param> @@ -733,142 +735,137 @@ namespace DiscImageChef.DiscImages base(message, inner) { } /// <summary> - /// Feature is supported by image but not implemented yet. + /// Feature is supported by image but not implemented yet. /// </summary> /// <param name="message">Message.</param> public FeatureSupportedButNotImplementedImageException(string message) : base(message) { } /// <summary> - /// Feature is supported by image but not implemented yet. + /// Feature is supported by image but not implemented yet. /// </summary> /// <param name="info">Info.</param> /// <param name="context">Context.</param> - protected FeatureSupportedButNotImplementedImageException(SerializationInfo info, - StreamingContext context) + protected FeatureSupportedButNotImplementedImageException(SerializationInfo info, StreamingContext context) { if(info == null) throw new ArgumentNullException(nameof(info)); } } /// <summary> - /// Feature is not supported by image. + /// Feature is not supported by image. /// </summary> [Serializable] public class FeatureUnsupportedImageException : Exception { /// <summary> - /// Feature is not supported by image. + /// Feature is not supported by image. /// </summary> /// <param name="message">Message.</param> /// <param name="inner">Inner.</param> public FeatureUnsupportedImageException(string message, Exception inner) : base(message, inner) { } /// <summary> - /// Feature is not supported by image. + /// Feature is not supported by image. /// </summary> /// <param name="message">Message.</param> public FeatureUnsupportedImageException(string message) : base(message) { } /// <summary> - /// Feature is not supported by image. + /// Feature is not supported by image. /// </summary> /// <param name="info">Info.</param> /// <param name="context">Context.</param> - protected FeatureUnsupportedImageException(SerializationInfo info, - StreamingContext context) + protected FeatureUnsupportedImageException(SerializationInfo info, StreamingContext context) { if(info == null) throw new ArgumentNullException(nameof(info)); } } /// <summary> - /// Feature is supported by image but not present on it. + /// Feature is supported by image but not present on it. /// </summary> [Serializable] public class FeatureNotPresentImageException : Exception { /// <summary> - /// Feature is supported by image but not present on it. + /// Feature is supported by image but not present on it. /// </summary> /// <param name="message">Message.</param> /// <param name="inner">Inner.</param> public FeatureNotPresentImageException(string message, Exception inner) : base(message, inner) { } /// <summary> - /// Feature is supported by image but not present on it. + /// Feature is supported by image but not present on it. /// </summary> /// <param name="message">Message.</param> public FeatureNotPresentImageException(string message) : base(message) { } /// <summary> - /// Feature is supported by image but not present on it. + /// Feature is supported by image but not present on it. /// </summary> /// <param name="info">Info.</param> /// <param name="context">Context.</param> - protected FeatureNotPresentImageException(SerializationInfo info, - StreamingContext context) + protected FeatureNotPresentImageException(SerializationInfo info, StreamingContext context) { if(info == null) throw new ArgumentNullException(nameof(info)); } } /// <summary> - /// Feature is supported by image but not by the disc it represents. + /// Feature is supported by image but not by the disc it represents. /// </summary> [Serializable] public class FeaturedNotSupportedByDiscImageException : Exception { /// <summary> - /// Feature is supported by image but not by the disc it represents. + /// Feature is supported by image but not by the disc it represents. /// </summary> /// <param name="message">Message.</param> /// <param name="inner">Inner.</param> public FeaturedNotSupportedByDiscImageException(string message, Exception inner) : base(message, inner) { } /// <summary> - /// Feature is supported by image but not by the disc it represents. + /// Feature is supported by image but not by the disc it represents. /// </summary> /// <param name="message">Message.</param> public FeaturedNotSupportedByDiscImageException(string message) : base(message) { } /// <summary> - /// Feature is supported by image but not by the disc it represents. + /// Feature is supported by image but not by the disc it represents. /// </summary> /// <param name="info">Info.</param> /// <param name="context">Context.</param> - protected FeaturedNotSupportedByDiscImageException(SerializationInfo info, - StreamingContext context) + protected FeaturedNotSupportedByDiscImageException(SerializationInfo info, StreamingContext context) { if(info == null) throw new ArgumentNullException(nameof(info)); } } /// <summary> - /// Corrupt, incorrect or unhandled feature found on image + /// Corrupt, incorrect or unhandled feature found on image /// </summary> [Serializable] public class ImageNotSupportedException : Exception { /// <summary> - /// Corrupt, incorrect or unhandled feature found on image + /// Corrupt, incorrect or unhandled feature found on image /// </summary> /// <param name="message">Message.</param> /// <param name="inner">Inner.</param> public ImageNotSupportedException(string message, Exception inner) : base(message, inner) { } /// <summary> - /// Corrupt, incorrect or unhandled feature found on image + /// Corrupt, incorrect or unhandled feature found on image /// </summary> /// <param name="message">Message.</param> public ImageNotSupportedException(string message) : base(message) { } /// <summary> - /// Corrupt, incorrect or unhandled feature found on image + /// Corrupt, incorrect or unhandled feature found on image /// </summary> /// <param name="info">Info.</param> /// <param name="context">Context.</param> - protected ImageNotSupportedException(SerializationInfo info, - StreamingContext context) + protected ImageNotSupportedException(SerializationInfo info, StreamingContext context) { if(info == null) throw new ArgumentNullException(nameof(info)); } diff --git a/DiscImageChef.DiscImages/KryoFlux.cs b/DiscImageChef.DiscImages/KryoFlux.cs index 2653a0041..bbfd868e7 100644 --- a/DiscImageChef.DiscImages/KryoFlux.cs +++ b/DiscImageChef.DiscImages/KryoFlux.cs @@ -46,45 +46,6 @@ namespace DiscImageChef.DiscImages [SuppressMessage("ReSharper", "InconsistentNaming")] public class KryoFlux : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct OobBlock - { - public BlockIds blockId; - public OobTypes blockType; - public ushort length; - } - #endregion Internal Structures - - #region Internal Constants - enum BlockIds : byte - { - Flux2 = 0x00, - Flux2_1 = 0x01, - Flux2_2 = 0x02, - Flux2_3 = 0x03, - Flux2_4 = 0x04, - Flux2_5 = 0x05, - Flux2_6 = 0x06, - Flux2_7 = 0x07, - Nop1 = 0x08, - Nop2 = 0x09, - Nop3 = 0x0A, - Ovl16 = 0x0B, - Flux3 = 0x0C, - Oob = 0x0D - } - - enum OobTypes : byte - { - Invalid = 0x00, - StreamInfo = 0x01, - Index = 0x02, - StreamEnd = 0x03, - KFInfo = 0x04, - EOF = 0x0D - } - const string hostDate = "host_date"; const string hostTime = "host_time"; const string kfName = "name"; @@ -95,12 +56,9 @@ namespace DiscImageChef.DiscImages const string kfHwRv = "hwrv"; const string kfSck = "sck"; const string kfIck = "ick"; - #endregion Internal Constants - #region Internal variables // TODO: These variables have been made public so create-sidecar can access to this information until I define an API >4.0 public SortedDictionary<byte, Filter> tracks; - #endregion Internal variables public KryoFlux() { @@ -131,7 +89,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { OobBlock header = new OobBlock(); @@ -192,7 +149,7 @@ namespace DiscImageChef.DiscImages footer.blockId != BlockIds.Oob || footer.blockType != OobTypes.EOF || footer.length != 0x0D0D) return false; - #region TODO: This is supposing NoFilter, shouldn't + // TODO: This is supposing NoFilter, shouldn't tracks = new SortedDictionary<byte, Filter>(); byte step = 1; byte heads = 2; @@ -285,12 +242,14 @@ namespace DiscImageChef.DiscImages DateTime blockTime = DateTime.Now; bool foundDate = false; - foreach(string[] kvp in lines.Select(line => line.Split('=')).Where(kvp => kvp.Length == 2)) { + foreach(string[] kvp in lines.Select(line => line.Split('=')).Where(kvp => kvp.Length == 2)) + { kvp[0] = kvp[0].Trim(); kvp[1] = kvp[1].Trim(); DicConsole.DebugWriteLine("KryoFlux plugin", "\"{0}\" = \"{1}\"", kvp[0], kvp[1]); - switch(kvp[0]) { + switch(kvp[0]) + { case hostDate: if(DateTime.TryParseExact(kvp[1], "yyyy.MM.dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out blockDate)) @@ -300,9 +259,11 @@ namespace DiscImageChef.DiscImages DateTime.TryParseExact(kvp[1], "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out blockTime); break; - case kfName: ImageInfo.ImageApplication = kvp[1]; + case kfName: + ImageInfo.ImageApplication = kvp[1]; break; - case kfVersion: ImageInfo.ImageApplicationVersion = kvp[1]; + case kfVersion: + ImageInfo.ImageApplicationVersion = kvp[1]; break; } } @@ -345,7 +306,6 @@ namespace DiscImageChef.DiscImages ImageInfo.Heads = heads; ImageInfo.Cylinders = (uint)(tracks.Count / heads); - #endregion TODO: This is supposing NoFilter, shouldn't throw new NotImplementedException("Flux decoding is not yet implemented."); } @@ -520,9 +480,7 @@ namespace DiscImageChef.DiscImages { throw new NotImplementedException("Flux decoding is not yet implemented."); } - #endregion Public methods - #region Unsupported features public override byte[] ReadSector(ulong sectorAddress, uint track) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -588,6 +546,41 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct OobBlock + { + public BlockIds blockId; + public OobTypes blockType; + public ushort length; + } + + enum BlockIds : byte + { + Flux2 = 0x00, + Flux2_1 = 0x01, + Flux2_2 = 0x02, + Flux2_3 = 0x03, + Flux2_4 = 0x04, + Flux2_5 = 0x05, + Flux2_6 = 0x06, + Flux2_7 = 0x07, + Nop1 = 0x08, + Nop2 = 0x09, + Nop3 = 0x0A, + Ovl16 = 0x0B, + Flux3 = 0x0C, + Oob = 0x0D + } + + enum OobTypes : byte + { + Invalid = 0x00, + StreamInfo = 0x01, + Index = 0x02, + StreamEnd = 0x03, + KFInfo = 0x04, + EOF = 0x0D + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/MaxiDisk.cs b/DiscImageChef.DiscImages/MaxiDisk.cs index 8a4dd05e4..00efcaf26 100644 --- a/DiscImageChef.DiscImages/MaxiDisk.cs +++ b/DiscImageChef.DiscImages/MaxiDisk.cs @@ -42,41 +42,8 @@ namespace DiscImageChef.DiscImages { public class MaxiDisk : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct HdkHeader - { - public byte unknown; - public byte diskType; - public byte heads; - public byte cylinders; - public byte bytesPerSector; - public byte sectorsPerTrack; - public byte unknown2; - public byte unknown3; - } - - enum HdkDiskTypes : byte - { - Dos360 = 0, - Maxi420 = 1, - Dos720 = 2, - Maxi800 = 3, - Dos1200 = 4, - Maxi1400 = 5, - Dos1440 = 6, - Mac1440 = 7, - Maxi1600 = 8, - Dmf = 9, - Dos2880 = 10, - Maxi3200 = 11 - } - #endregion - - #region Internal variables /// <summary>Disk image file</summary> Filter hdkImageFilter; - #endregion public MaxiDisk() { @@ -390,7 +357,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -510,6 +476,34 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct HdkHeader + { + public byte unknown; + public byte diskType; + public byte heads; + public byte cylinders; + public byte bytesPerSector; + public byte sectorsPerTrack; + public byte unknown2; + public byte unknown3; + } + + enum HdkDiskTypes : byte + { + Dos360 = 0, + Maxi420 = 1, + Dos720 = 2, + Maxi800 = 3, + Dos1200 = 4, + Maxi1400 = 5, + Dos1440 = 6, + Mac1440 = 7, + Maxi1600 = 8, + Dmf = 9, + Dos2880 = 10, + Maxi3200 = 11 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/NDIF.cs b/DiscImageChef.DiscImages/NDIF.cs index 14cab274a..436a077cb 100644 --- a/DiscImageChef.DiscImages/NDIF.cs +++ b/DiscImageChef.DiscImages/NDIF.cs @@ -40,7 +40,6 @@ using Claunia.RsrcFork; using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.Filters; -using SharpCompress.Compressors; using SharpCompress.Compressors.ADC; using Version = Resources.Version; @@ -52,124 +51,14 @@ namespace DiscImageChef.DiscImages // TODO: Implement compression public class Ndif : ImagePlugin { - #region Internal constants /// <summary> - /// Resource OSType for NDIF is "bcem" + /// Resource OSType for NDIF is "bcem" /// </summary> const uint NDIF_RESOURCE = 0x6263656D; /// <summary> - /// Resource ID is always 128? Never found another + /// Resource ID is always 128? Never found another /// </summary> const short NDIF_RESOURCEID = 128; - #endregion - - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ChunkHeader - { - /// <summary> - /// Version - /// </summary> - public short version; - /// <summary> - /// Filesystem ID - /// </summary> - public short driver; - /// <summary> - /// Disk image name, Str63 (Pascal string) - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] name; - /// <summary> - /// Sectors in image - /// </summary> - public uint sectors; - /// <summary> - /// Maximum number of sectors per chunk - /// </summary> - public uint maxSectorsPerChunk; - /// <summary> - /// Offset to add to every chunk offset - /// </summary> - public uint dataOffset; - /// <summary> - /// CRC28 of whole image - /// </summary> - public uint crc; - /// <summary> - /// Set to 1 if segmented - /// </summary> - public uint segmented; - /// <summary> - /// Unknown - /// </summary> - public uint p1; - /// <summary> - /// Unknown - /// </summary> - public uint p2; - /// <summary> - /// Unknown, spare? - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public uint[] unknown; - /// <summary> - /// Set to 1 by ShrinkWrap if image is encrypted - /// </summary> - public uint encrypted; - /// <summary> - /// Set by ShrinkWrap if image is encrypted, value is the same for same password - /// </summary> - public uint hash; - /// <summary> - /// How many chunks follow the header - /// </summary> - public uint chunks; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BlockChunk - { - /// <summary> - /// Starting sector, 3 bytes - /// </summary> - public uint sector; - /// <summary> - /// Chunk type - /// </summary> - public byte type; - /// <summary> - /// Offset in start of chunk - /// </summary> - public uint offset; - /// <summary> - /// Length in bytes of chunk - /// </summary> - public uint length; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SegmentHeader - { - /// <summary> - /// Segment # - /// </summary> - public ushort segment; - /// <summary> - /// How many segments - /// </summary> - public ushort segments; - /// <summary> - /// Seems to be a Guid, changes with different images, same for all segments of same image - /// </summary> - public Guid segmentId; - /// <summary> - /// Seems to be a CRC28 of this segment, unchecked - /// </summary> - public uint crc; - } - #endregion - - ChunkHeader header; - Dictionary<ulong, BlockChunk> chunks; const byte CHUNK_TYPE_NOCOPY = 0; const byte CHUNK_TYPE_COPY = 2; @@ -178,7 +67,7 @@ namespace DiscImageChef.DiscImages const byte CHUNK_TYPE_LZH = 0x82; const byte CHUNK_TYPE_ADC = 0x83; /// <summary> - /// Created by ShrinkWrap 3.5, dunno which version of the StuffIt algorithm it is using + /// Created by ShrinkWrap 3.5, dunno which version of the StuffIt algorithm it is using /// </summary> const byte CHUNK_TYPE_STUFFIT = 0xF0; const byte CHUNK_TYPE_END = 0xFF; @@ -189,17 +78,20 @@ namespace DiscImageChef.DiscImages const short DRIVER_HFS = 0; const short DRIVER_PRODOS = 256; const short DRIVER_DOS = 18771; - - Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> chunkCache; const uint MAX_CACHE_SIZE = 16777216; const uint SECTOR_SIZE = 512; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / SECTOR_SIZE; - uint currentChunkCacheSize; uint buffersize; + Dictionary<ulong, byte[]> chunkCache; + Dictionary<ulong, BlockChunk> chunks; + uint currentChunkCacheSize; + + ChunkHeader header; Stream imageStream; + Dictionary<ulong, byte[]> sectorCache; + public Ndif() { Name = "Apple New Disk Image Format"; @@ -269,7 +161,8 @@ namespace DiscImageChef.DiscImages catch(InvalidCastException) { return false; } ImageInfo.Sectors = 0; - foreach(byte[] bcem in bcems.Select(id => rsrc.GetResource(NDIF_RESOURCEID))) { + foreach(byte[] bcem in bcems.Select(id => rsrc.GetResource(NDIF_RESOURCEID))) + { if(bcem.Length < 128) return false; header = BigEndianMarshal.ByteArrayToStructureBigEndian<ChunkHeader>(bcem); @@ -323,11 +216,18 @@ namespace DiscImageChef.DiscImages bChnk.sector += (uint)ImageInfo.Sectors; // TODO: Handle compressed chunks - switch(bChnk.type) { - case CHUNK_TYPE_KENCODE: throw new ImageNotSupportedException("Chunks compressed with KenCode are not yet supported."); - case CHUNK_TYPE_RLE: throw new ImageNotSupportedException("Chunks compressed with RLE are not yet supported."); - case CHUNK_TYPE_LZH: throw new ImageNotSupportedException("Chunks compressed with LZH are not yet supported."); - case CHUNK_TYPE_STUFFIT: throw new ImageNotSupportedException("Chunks compressed with StuffIt! are not yet supported."); + switch(bChnk.type) + { + case CHUNK_TYPE_KENCODE: + throw new + ImageNotSupportedException("Chunks compressed with KenCode are not yet supported."); + case CHUNK_TYPE_RLE: + throw new ImageNotSupportedException("Chunks compressed with RLE are not yet supported."); + case CHUNK_TYPE_LZH: + throw new ImageNotSupportedException("Chunks compressed with LZH are not yet supported."); + case CHUNK_TYPE_STUFFIT: + throw new + ImageNotSupportedException("Chunks compressed with StuffIt! are not yet supported."); } // TODO: Handle compressed chunks @@ -471,7 +371,8 @@ namespace DiscImageChef.DiscImages bool chunkFound = false; ulong chunkStartSector = 0; - foreach(KeyValuePair<ulong, BlockChunk> kvp in chunks.Where(kvp => sectorAddress >= kvp.Key)) { + foreach(KeyValuePair<ulong, BlockChunk> kvp in chunks.Where(kvp => sectorAddress >= kvp.Key)) + { currentChunk = kvp.Value; chunkFound = true; chunkStartSector = kvp.Key; @@ -498,8 +399,7 @@ namespace DiscImageChef.DiscImages Stream decStream; if(currentChunk.type == CHUNK_TYPE_ADC) decStream = new ADCStream(cmpMs); - else - throw new ImageNotSupportedException($"Unsupported chunk type 0x{currentChunk.type:X8} found"); + else throw new ImageNotSupportedException($"Unsupported chunk type 0x{currentChunk.type:X8} found"); byte[] tmpBuffer = new byte[buffersize]; int realSize = decStream.Read(tmpBuffer, 0, (int)buffersize); @@ -526,7 +426,8 @@ namespace DiscImageChef.DiscImages return sector; } - switch(currentChunk.type) { + switch(currentChunk.type) + { case CHUNK_TYPE_NOCOPY: sector = new byte[SECTOR_SIZE]; @@ -638,7 +539,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -799,6 +699,108 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ChunkHeader + { + /// <summary> + /// Version + /// </summary> + public short version; + /// <summary> + /// Filesystem ID + /// </summary> + public short driver; + /// <summary> + /// Disk image name, Str63 (Pascal string) + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] name; + /// <summary> + /// Sectors in image + /// </summary> + public uint sectors; + /// <summary> + /// Maximum number of sectors per chunk + /// </summary> + public uint maxSectorsPerChunk; + /// <summary> + /// Offset to add to every chunk offset + /// </summary> + public uint dataOffset; + /// <summary> + /// CRC28 of whole image + /// </summary> + public uint crc; + /// <summary> + /// Set to 1 if segmented + /// </summary> + public uint segmented; + /// <summary> + /// Unknown + /// </summary> + public uint p1; + /// <summary> + /// Unknown + /// </summary> + public uint p2; + /// <summary> + /// Unknown, spare? + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public uint[] unknown; + /// <summary> + /// Set to 1 by ShrinkWrap if image is encrypted + /// </summary> + public uint encrypted; + /// <summary> + /// Set by ShrinkWrap if image is encrypted, value is the same for same password + /// </summary> + public uint hash; + /// <summary> + /// How many chunks follow the header + /// </summary> + public uint chunks; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BlockChunk + { + /// <summary> + /// Starting sector, 3 bytes + /// </summary> + public uint sector; + /// <summary> + /// Chunk type + /// </summary> + public byte type; + /// <summary> + /// Offset in start of chunk + /// </summary> + public uint offset; + /// <summary> + /// Length in bytes of chunk + /// </summary> + public uint length; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SegmentHeader + { + /// <summary> + /// Segment # + /// </summary> + public ushort segment; + /// <summary> + /// How many segments + /// </summary> + public ushort segments; + /// <summary> + /// Seems to be a Guid, changes with different images, same for all segments of same image + /// </summary> + public Guid segmentId; + /// <summary> + /// Seems to be a CRC28 of this segment, unchecked + /// </summary> + public uint crc; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/NHDr0.cs b/DiscImageChef.DiscImages/NHDr0.cs index 14645cfcc..fff71c508 100644 --- a/DiscImageChef.DiscImages/NHDr0.cs +++ b/DiscImageChef.DiscImages/NHDr0.cs @@ -45,26 +45,12 @@ namespace DiscImageChef.DiscImages // Info from http://www.geocities.jp/t98next/nhdr0.txt public class Nhdr0 : ImagePlugin { - #region Internal structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Nhdr0Header - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] szFileID; - public byte reserved1; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] public byte[] szComment; - public int dwHeadSize; - public int dwCylinder; - public short wHead; - public short wSect; - public short wSectLen; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved2; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xE0)] public byte[] reserved3; - } - #endregion - readonly byte[] signature = {0x54, 0x39, 0x38, 0x48, 0x44, 0x44, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x2E, 0x52, 0x30, 0x00}; + Nhdr0Header nhdhdr; + Filter nhdImageFilter; + public Nhdr0() { Name = "T98-Next NHD r0 Disk Image"; @@ -94,9 +80,6 @@ namespace DiscImageChef.DiscImages }; } - Nhdr0Header nhdhdr; - Filter nhdImageFilter; - public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -262,7 +245,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -423,6 +405,20 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Nhdr0Header + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] szFileID; + public byte reserved1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] public byte[] szComment; + public int dwHeadSize; + public int dwCylinder; + public short wHead; + public short wSect; + public short wSectLen; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xE0)] public byte[] reserved3; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Nero.cs b/DiscImageChef.DiscImages/Nero.cs index bed6a42bb..3b0b2abcc 100644 --- a/DiscImageChef.DiscImages/Nero.cs +++ b/DiscImageChef.DiscImages/Nero.cs @@ -40,6 +40,7 @@ using DiscImageChef.Checksums; using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.Filters; + #pragma warning disable 414 #pragma warning disable 169 @@ -49,566 +50,6 @@ namespace DiscImageChef.DiscImages [SuppressMessage("ReSharper", "CollectionNeverQueried.Local")] public class Nero : ImagePlugin { - #region Internal structures - struct NeroV1Footer - { - /// <summary> - /// "NERO" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Offset of first chunk in file - /// </summary> - public uint FirstChunkOffset; - } - - struct NeroV2Footer - { - /// <summary> - /// "NER5" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Offset of first chunk in file - /// </summary> - public ulong FirstChunkOffset; - } - - struct NeroV2CueEntry - { - /// <summary> - /// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data - /// </summary> - public byte Mode; - - /// <summary> - /// Track number in BCD - /// </summary> - public byte TrackNumber; - - /// <summary> - /// Index number in BCD - /// </summary> - public byte IndexNumber; - - /// <summary> - /// Always zero - /// </summary> - public byte Dummy; - - /// <summary> - /// LBA sector start for this entry - /// </summary> - public int LbaStart; - } - - struct NeroV2Cuesheet - { - /// <summary> - /// "CUEX" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Cuesheet entries - /// </summary> - public List<NeroV2CueEntry> Entries; - } - - struct NeroV1CueEntry - { - /// <summary> - /// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data - /// </summary> - public byte Mode; - - /// <summary> - /// Track number in BCD - /// </summary> - public byte TrackNumber; - - /// <summary> - /// Index number in BCD - /// </summary> - public byte IndexNumber; - - /// <summary> - /// Always zero - /// </summary> - public ushort Dummy; - - /// <summary> - /// MSF start sector's minute for this entry - /// </summary> - public byte Minute; - - /// <summary> - /// MSF start sector's second for this entry - /// </summary> - public byte Second; - - /// <summary> - /// MSF start sector's frame for this entry - /// </summary> - public byte Frame; - } - - struct NeroV1Cuesheet - { - /// <summary> - /// "CUES" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Cuesheet entries - /// </summary> - public List<NeroV1CueEntry> Entries; - } - - struct NeroV1DaoEntry - { - /// <summary> - /// ISRC (12 bytes) - /// </summary> - public byte[] Isrc; - - /// <summary> - /// Size of sector inside image (in bytes) - /// </summary> - public ushort SectorSize; - - /// <summary> - /// Sector mode in image - /// </summary> - public ushort Mode; - - /// <summary> - /// Unknown - /// </summary> - public ushort Unknown; - - /// <summary> - /// Index 0 start - /// </summary> - public uint Index0; - - /// <summary> - /// Index 1 start - /// </summary> - public uint Index1; - - /// <summary> - /// End of track + 1 - /// </summary> - public uint EndOfTrack; - } - - struct NeroV1Dao - { - /// <summary> - /// "DAOI" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size (big endian) - /// </summary> - public uint ChunkSizeBe; - - /// <summary> - /// Chunk size (little endian) - /// </summary> - public uint ChunkSizeLe; - - /// <summary> - /// UPC (14 bytes, null-padded) - /// </summary> - public byte[] Upc; - - /// <summary> - /// TOC type - /// </summary> - public ushort TocType; - - /// <summary> - /// First track - /// </summary> - public byte FirstTrack; - - /// <summary> - /// Last track - /// </summary> - public byte LastTrack; - - /// <summary> - /// Tracks - /// </summary> - public List<NeroV1DaoEntry> Tracks; - } - - struct NeroV2DaoEntry - { - /// <summary> - /// ISRC (12 bytes) - /// </summary> - public byte[] Isrc; - - /// <summary> - /// Size of sector inside image (in bytes) - /// </summary> - public ushort SectorSize; - - /// <summary> - /// Sector mode in image - /// </summary> - public ushort Mode; - - /// <summary> - /// Seems to be always 0. - /// </summary> - public ushort Unknown; - - /// <summary> - /// Index 0 start - /// </summary> - public ulong Index0; - - /// <summary> - /// Index 1 start - /// </summary> - public ulong Index1; - - /// <summary> - /// End of track + 1 - /// </summary> - public ulong EndOfTrack; - } - - struct NeroV2Dao - { - /// <summary> - /// "DAOX" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size (big endian) - /// </summary> - public uint ChunkSizeBe; - - /// <summary> - /// Chunk size (little endian) - /// </summary> - public uint ChunkSizeLe; - - /// <summary> - /// UPC (14 bytes, null-padded) - /// </summary> - public byte[] Upc; - - /// <summary> - /// TOC type - /// </summary> - public ushort TocType; - - /// <summary> - /// First track - /// </summary> - public byte FirstTrack; - - /// <summary> - /// Last track - /// </summary> - public byte LastTrack; - - /// <summary> - /// Tracks - /// </summary> - public List<NeroV2DaoEntry> Tracks; - } - - struct NeroCdTextPack - { - /// <summary> - /// Pack type - /// </summary> - public byte PackType; - - /// <summary> - /// Track number - /// </summary> - public byte TrackNumber; - - /// <summary> - /// Pack number in block - /// </summary> - public byte PackNumber; - - /// <summary> - /// Block number - /// </summary> - public byte BlockNumber; - - /// <summary> - /// 12 bytes of data - /// </summary> - public byte[] Text; - - /// <summary> - /// CRC - /// </summary> - public ushort Crc; - } - - struct NeroCdText - { - /// <summary> - /// "CDTX" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// CD-TEXT packs - /// </summary> - public List<NeroCdTextPack> Packs; - } - - struct NeroV1TaoEntry - { - /// <summary> - /// Offset of track on image - /// </summary> - public uint Offset; - - /// <summary> - /// Length of track in bytes - /// </summary> - public uint Length; - - /// <summary> - /// Track mode - /// </summary> - public uint Mode; - - /// <summary> - /// LBA track start (plus 150 lead in sectors) - /// </summary> - public uint StartLba; - - /// <summary> - /// Unknown - /// </summary> - public uint Unknown; - } - - struct NeroV1Tao - { - /// <summary> - /// "ETNF" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// CD-TEXT packs - /// </summary> - public List<NeroV1TaoEntry> Tracks; - } - - struct NeroV2TaoEntry - { - /// <summary> - /// Offset of track on image - /// </summary> - public ulong Offset; - - /// <summary> - /// Length of track in bytes - /// </summary> - public ulong Length; - - /// <summary> - /// Track mode - /// </summary> - public uint Mode; - - /// <summary> - /// LBA track start (plus 150 lead in sectors) - /// </summary> - public uint StartLba; - - /// <summary> - /// Unknown - /// </summary> - public uint Unknown; - - /// <summary> - /// Track length in sectors - /// </summary> - public uint Sectors; - } - - struct NeroV2Tao - { - /// <summary> - /// "ETN2" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// CD-TEXT packs - /// </summary> - public List<NeroV2TaoEntry> Tracks; - } - - struct NeroSession - { - /// <summary> - /// "SINF" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Tracks in session - /// </summary> - public uint Tracks; - } - - struct NeroMediaType - { - /// <summary> - /// "MTYP" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Media type - /// </summary> - public uint Type; - } - - struct NeroDiscInformation - { - /// <summary> - /// "DINF" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Unknown - /// </summary> - public uint Unknown; - } - - struct NeroTocChunk - { - /// <summary> - /// "TOCT" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Unknown - /// </summary> - public ushort Unknown; - } - - struct NeroReloChunk - { - /// <summary> - /// "RELO" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - - /// <summary> - /// Unknown - /// </summary> - public uint Unknown; - } - - struct NeroEndOfChunkChain - { - /// <summary> - /// "END!" - /// </summary> - public uint ChunkId; - - /// <summary> - /// Chunk size - /// </summary> - public uint ChunkSize; - } - - // Internal use only - struct NeroTrack - { - public byte[] Isrc; - public ushort SectorSize; - public ulong Offset; - public ulong Length; - public ulong EndOfTrack; - public uint Mode; - public ulong StartLba; - public ulong Sectors; - public ulong Index0; - public ulong Index1; - public uint Sequence; - } - #endregion - - #region Internal consts // "NERO" const uint NERO_FOOTER_V1 = 0x4E45524F; @@ -653,218 +94,31 @@ namespace DiscImageChef.DiscImages // "END!" const uint NERO_END = 0x454E4421; - - enum DaoMode : ushort - { - Data = 0x0000, - DataM2F1 = 0x0002, - DataM2F2 = 0x0003, - DataRaw = 0x0005, - DataM2Raw = 0x0006, - Audio = 0x0007, - DataRawSub = 0x000F, - AudioSub = 0x0010, - DataM2RawSub = 0x0011 - } - - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - enum NeroMediaTypes : uint - { - /// <summary> - /// No media - /// </summary> - NeroMtypNone = 0x00000, - /// <summary> - /// CD-R/RW - /// </summary> - NeroMtypCd = 0x00001, - /// <summary> - /// DDCD-R/RW - /// </summary> - NeroMtypDdcd = 0x00002, - /// <summary> - /// DVD-R/RW - /// </summary> - NeroMtypDvdM = 0x00004, - /// <summary> - /// DVD+RW - /// </summary> - NeroMtypDvdP = 0x00008, - /// <summary> - /// DVD-RAM - /// </summary> - NeroMtypDvdRam = 0x00010, - /// <summary> - /// Multi-level disc - /// </summary> - NeroMtypMl = 0x00020, - /// <summary> - /// Mount Rainier - /// </summary> - NeroMtypMrw = 0x00040, - /// <summary> - /// Exclude CD-R - /// </summary> - NeroMtypNoCdr = 0x00080, - /// <summary> - /// Exclude CD-RW - /// </summary> - NeroMtypNoCdrw = 0x00100, - /// <summary> - /// CD-RW - /// </summary> - NeroMtypCdrw = NeroMtypCd | NeroMtypNoCdr, - /// <summary> - /// CD-R - /// </summary> - NeroMtypCdr = NeroMtypCd | NeroMtypNoCdrw, - /// <summary> - /// DVD-ROM - /// </summary> - NeroMtypDvdRom = 0x00200, - /// <summary> - /// CD-ROM - /// </summary> - NeroMtypCdrom = 0x00400, - /// <summary> - /// Exclude DVD-RW - /// </summary> - NeroMtypNoDvdMRw = 0x00800, - /// <summary> - /// Exclude DVD-R - /// </summary> - NeroMtypNoDvdMR = 0x01000, - /// <summary> - /// Exclude DVD+RW - /// </summary> - NeroMtypNoDvdPRw = 0x02000, - /// <summary> - /// Exclude DVD+R - /// </summary> - NeroMtypNoDvdPR = 0x04000, - /// <summary> - /// DVD-R - /// </summary> - NeroMtypDvdMR = NeroMtypDvdM | NeroMtypNoDvdMRw, - /// <summary> - /// DVD-RW - /// </summary> - NeroMtypDvdMRw = NeroMtypDvdM | NeroMtypNoDvdMR, - /// <summary> - /// DVD+R - /// </summary> - NeroMtypDvdPR = NeroMtypDvdP | NeroMtypNoDvdPRw, - /// <summary> - /// DVD+RW - /// </summary> - NeroMtypDvdPRw = NeroMtypDvdP | NeroMtypNoDvdPR, - /// <summary> - /// Packet-writing (fixed) - /// </summary> - NeroMtypFpacket = 0x08000, - /// <summary> - /// Packet-writing (variable) - /// </summary> - NeroMtypVpacket = 0x10000, - /// <summary> - /// Packet-writing (any) - /// </summary> - NeroMtypPacketw = NeroMtypMrw | NeroMtypFpacket | NeroMtypVpacket, - /// <summary> - /// HD-Burn - /// </summary> - NeroMtypHdb = 0x20000, - /// <summary> - /// DVD+R DL - /// </summary> - NeroMtypDvdPR9 = 0x40000, - /// <summary> - /// DVD-R DL - /// </summary> - NeroMtypDvdMR9 = 0x80000, - /// <summary> - /// Any DVD double-layer - /// </summary> - NeroMtypDvdAnyR9 = NeroMtypDvdPR9 | NeroMtypDvdMR9, - /// <summary> - /// Any DVD - /// </summary> - NeroMtypDvdAny = NeroMtypDvdM | NeroMtypDvdP | NeroMtypDvdRam | NeroMtypDvdAnyR9, - /// <summary> - /// BD-ROM - /// </summary> - NeroMtypBdRom = 0x100000, - /// <summary> - /// BD-R - /// </summary> - NeroMtypBdR = 0x200000, - /// <summary> - /// BD-RE - /// </summary> - NeroMtypBdRe = 0x400000, - /// <summary> - /// BD-R/RE - /// </summary> - NeroMtypBd = NeroMtypBdR | NeroMtypBdRe, - /// <summary> - /// Any BD - /// </summary> - NeroMtypBdAny = NeroMtypBd | NeroMtypBdRom, - /// <summary> - /// HD DVD-ROM - /// </summary> - NeroMtypHdDvdRom = 0x0800000, - /// <summary> - /// HD DVD-R - /// </summary> - NeroMtypHdDvdR = 0x1000000, - /// <summary> - /// HD DVD-RW - /// </summary> - NeroMtypHdDvdRw = 0x2000000, - /// <summary> - /// HD DVD-R/RW - /// </summary> - NeroMtypHdDvd = NeroMtypHdDvdR | NeroMtypHdDvdRw, - /// <summary> - /// Any HD DVD - /// </summary> - NeroMtypHdDvdAny = NeroMtypHdDvd | NeroMtypHdDvdRom, - /// <summary> - /// Any DVD, old - /// </summary> - NeroMtypDvdAnyOld = NeroMtypDvdM | NeroMtypDvdP | NeroMtypDvdRam - } - #endregion - - #region Internal variables - Filter neroFilter; - Stream imageStream; bool imageNewFormat; - Dictionary<ushort, uint> neroSessions; + List<Partition> imagePartitions; + List<Session> imageSessions; + Stream imageStream; + + List<Track> imageTracks; + NeroCdText neroCdtxt; NeroV1Cuesheet neroCuesheetV1; NeroV2Cuesheet neroCuesheetV2; NeroV1Dao neroDaov1; NeroV2Dao neroDaov2; - NeroCdText neroCdtxt; + NeroDiscInformation neroDiscInfo; + + Filter neroFilter; + NeroMediaType neroMediaTyp; + NeroReloChunk neroRelo; + Dictionary<ushort, uint> neroSessions; NeroV1Tao neroTaov1; NeroV2Tao neroTaov2; - NeroMediaType neroMediaTyp; - NeroDiscInformation neroDiscInfo; NeroTocChunk neroToc; - NeroReloChunk neroRelo; - - List<Track> imageTracks; - Dictionary<uint, byte[]> trackIsrCs; - byte[] upc; Dictionary<uint, NeroTrack> neroTracks; Dictionary<uint, ulong> offsetmap; - List<Session> imageSessions; - List<Partition> imagePartitions; - #endregion + Dictionary<uint, byte[]> trackIsrCs; + byte[] upc; - #region Methods public Nero() { Name = "Nero Burning ROM image"; @@ -938,12 +192,10 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("Nero plugin", "imageStream.Length = {0}", imageStream.Length); DicConsole.DebugWriteLine("Nero plugin", "footerV1.ChunkID = 0x{0:X8} (\"{1}\")", footerV1.ChunkId, - Encoding.ASCII - .GetString(BigEndianBitConverter.GetBytes(footerV1.ChunkId))); + Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(footerV1.ChunkId))); DicConsole.DebugWriteLine("Nero plugin", "footerV1.FirstChunkOffset = {0}", footerV1.FirstChunkOffset); DicConsole.DebugWriteLine("Nero plugin", "footerV2.ChunkID = 0x{0:X8} (\"{1}\")", footerV2.ChunkId, - Encoding.ASCII - .GetString(BigEndianBitConverter.GetBytes(footerV2.ChunkId))); + Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(footerV2.ChunkId))); DicConsole.DebugWriteLine("Nero plugin", "footerV2.FirstChunkOffset = {0}", footerV2.FirstChunkOffset); if(footerV1.ChunkId == NERO_FOOTER_V1 && footerV1.FirstChunkOffset < (ulong)imageStream.Length) @@ -981,8 +233,7 @@ namespace DiscImageChef.DiscImages chunkLength = BigEndianBitConverter.ToUInt32(chunkHeaderBuffer, 4); DicConsole.DebugWriteLine("Nero plugin", "ChunkID = 0x{0:X8} (\"{1}\")", chunkId, - Encoding.ASCII - .GetString(BigEndianBitConverter.GetBytes(chunkId))); + Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(chunkId))); DicConsole.DebugWriteLine("Nero plugin", "ChunkLength = {0}", chunkLength); switch(chunkId) @@ -1124,8 +375,8 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("Nero plugin", "Disc-At-Once entry {0}", i / 32 + 1); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].ISRC = \"{1}\"", i / 32 + 1, StringHandlers.CToString(entry.Isrc)); - DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", - i / 32 + 1, entry.SectorSize); + DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", i / 32 + 1, + entry.SectorSize); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", i / 32 + 1, (DaoMode)entry.Mode, entry.Mode); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = 0x{1:X4}", @@ -1134,8 +385,8 @@ namespace DiscImageChef.DiscImages entry.Index0); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index1 = {1}", i / 32 + 1, entry.Index1); - DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", - i / 32 + 1, entry.EndOfTrack); + DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", i / 32 + 1, + entry.EndOfTrack); neroDaov1.Tracks.Add(entry); @@ -1218,18 +469,18 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("Nero plugin", "Disc-At-Once entry {0}", i / 32 + 1); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].ISRC = \"{1}\"", i / 32 + 1, StringHandlers.CToString(entry.Isrc)); - DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", - i / 32 + 1, entry.SectorSize); + DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", i / 32 + 1, + entry.SectorSize); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", i / 32 + 1, (DaoMode)entry.Mode, entry.Mode); - DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = {1:X2}", - i / 32 + 1, entry.Unknown); + DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = {1:X2}", i / 32 + 1, + entry.Unknown); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index0 = {1}", i / 32 + 1, entry.Index0); DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index1 = {1}", i / 32 + 1, entry.Index1); - DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", - i / 32 + 1, entry.EndOfTrack); + DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", i / 32 + 1, + entry.EndOfTrack); neroDaov2.Tracks.Add(entry); @@ -1530,7 +781,7 @@ namespace DiscImageChef.DiscImages { DicConsole.DebugWriteLine("Nero plugin", "Unknown chunk ID \"{0}\", skipping...", Encoding.ASCII.GetString(BigEndianBitConverter - .GetBytes(chunkId))); + .GetBytes(chunkId))); imageStream.Seek(chunkLength, SeekOrigin.Current); break; } @@ -1585,8 +836,7 @@ namespace DiscImageChef.DiscImages if(!neroTracks.TryGetValue(i, out NeroTrack neroTrack)) continue; DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsession = {0}", currentsession); - DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsessionmaxtrack = {0}", - currentsessionmaxtrack); + DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsessionmaxtrack = {0}", currentsessionmaxtrack); DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsessioncurrenttrack = {0}", currentsessioncurrenttrack); @@ -1660,25 +910,21 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackDescription = {0}", track.TrackDescription); - DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackEndSector = {0}", - track.TrackEndSector); + DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackEndSector = {0}", track.TrackEndSector); DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackPregap = {0}", track.TrackPregap); - DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackSequence = {0}", - track.TrackSequence); + DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackSequence = {0}", track.TrackSequence); DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackSession = {0}", track.TrackSession); DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackStartSector = {0}", track.TrackStartSector); DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackType = {0}", track.TrackType); if(currentsessioncurrenttrack == 1) - { currentsessionstruct = new Session - { + { SessionSequence = currentsession, StartSector = track.TrackStartSector, StartTrack = track.TrackSequence }; - } currentsessioncurrenttrack++; if(currentsessioncurrenttrack > currentsessionmaxtrack) { @@ -1751,10 +997,12 @@ namespace DiscImageChef.DiscImages (DaoMode)neroTracks.ElementAt(i).Value.Mode == DaoMode.AudioSub); // First track is data - firstdata |= i == 0 && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.Audio && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.AudioSub; + firstdata |= i == 0 && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.Audio && + (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.AudioSub; // Any non first track is data - data |= i != 0 && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.Audio && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.AudioSub; + data |= i != 0 && (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.Audio && + (DaoMode)neroTracks.ElementAt(i).Value.Mode != DaoMode.AudioSub; // Any non first track is audio audio |= i != 0 && ((DaoMode)neroTracks.ElementAt(i).Value.Mode == DaoMode.Audio || @@ -1845,14 +1093,28 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectors(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in imageTracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in imageTracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in imageTracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in imageTracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -1937,9 +1199,8 @@ namespace DiscImageChef.DiscImages imageStream = neroFilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); - br.BaseStream - .Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), - SeekOrigin.Begin); + br.BaseStream.Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), + SeekOrigin.Begin); if(sectorOffset == 0 && sectorSkip == 0) buffer = br.ReadBytes((int)(sectorSize * length)); else for(int i = 0; i < length; i++) @@ -2161,9 +1422,8 @@ namespace DiscImageChef.DiscImages imageStream = neroFilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); - br.BaseStream - .Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), - SeekOrigin.Begin); + br.BaseStream.Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), + SeekOrigin.Begin); if(sectorOffset == 0 && sectorSkip == 0) buffer = br.ReadBytes((int)(sectorSize * length)); else for(int i = 0; i < length; i++) @@ -2189,7 +1449,14 @@ namespace DiscImageChef.DiscImages public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { - foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in imageTracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); + foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap + where sectorAddress >= kvp.Value + from track in imageTracks + where track.TrackSequence == kvp.Key + where sectorAddress - kvp.Value < + track.TrackEndSector - track.TrackStartSector + select kvp) + return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key); throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); } @@ -2250,9 +1517,8 @@ namespace DiscImageChef.DiscImages imageStream = neroFilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); - br.BaseStream - .Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), - SeekOrigin.Begin); + br.BaseStream.Seek((long)dicTrack.Offset + (long)(sectorAddress * (sectorOffset + sectorSize + sectorSkip)), + SeekOrigin.Begin); if(sectorOffset == 0 && sectorSkip == 0) buffer = br.ReadBytes((int)(sectorSize * length)); else @@ -2401,18 +1667,15 @@ namespace DiscImageChef.DiscImages } if(unknownLbas.Count > 0) return null; - if(failingLbas.Count > 0) return false; - return true; + return failingLbas.Count <= 0; } public override bool? VerifyMediaImage() { return null; } - #endregion - #region Private methods static MediaType NeroMediaTypeToMediaType(NeroMediaTypes type) { switch(type) @@ -2483,9 +1746,7 @@ namespace DiscImageChef.DiscImages default: return 2352; } } - #endregion - #region Unsupported features public override int GetMediaSequence() { return ImageInfo.MediaSequence; @@ -2545,6 +1806,745 @@ namespace DiscImageChef.DiscImages { return ImageInfo.MediaSerialNumber; } - #endregion + + struct NeroV1Footer + { + /// <summary> + /// "NERO" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Offset of first chunk in file + /// </summary> + public uint FirstChunkOffset; + } + + struct NeroV2Footer + { + /// <summary> + /// "NER5" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Offset of first chunk in file + /// </summary> + public ulong FirstChunkOffset; + } + + struct NeroV2CueEntry + { + /// <summary> + /// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data + /// </summary> + public byte Mode; + + /// <summary> + /// Track number in BCD + /// </summary> + public byte TrackNumber; + + /// <summary> + /// Index number in BCD + /// </summary> + public byte IndexNumber; + + /// <summary> + /// Always zero + /// </summary> + public byte Dummy; + + /// <summary> + /// LBA sector start for this entry + /// </summary> + public int LbaStart; + } + + struct NeroV2Cuesheet + { + /// <summary> + /// "CUEX" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Cuesheet entries + /// </summary> + public List<NeroV2CueEntry> Entries; + } + + struct NeroV1CueEntry + { + /// <summary> + /// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data + /// </summary> + public byte Mode; + + /// <summary> + /// Track number in BCD + /// </summary> + public byte TrackNumber; + + /// <summary> + /// Index number in BCD + /// </summary> + public byte IndexNumber; + + /// <summary> + /// Always zero + /// </summary> + public ushort Dummy; + + /// <summary> + /// MSF start sector's minute for this entry + /// </summary> + public byte Minute; + + /// <summary> + /// MSF start sector's second for this entry + /// </summary> + public byte Second; + + /// <summary> + /// MSF start sector's frame for this entry + /// </summary> + public byte Frame; + } + + struct NeroV1Cuesheet + { + /// <summary> + /// "CUES" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Cuesheet entries + /// </summary> + public List<NeroV1CueEntry> Entries; + } + + struct NeroV1DaoEntry + { + /// <summary> + /// ISRC (12 bytes) + /// </summary> + public byte[] Isrc; + + /// <summary> + /// Size of sector inside image (in bytes) + /// </summary> + public ushort SectorSize; + + /// <summary> + /// Sector mode in image + /// </summary> + public ushort Mode; + + /// <summary> + /// Unknown + /// </summary> + public ushort Unknown; + + /// <summary> + /// Index 0 start + /// </summary> + public uint Index0; + + /// <summary> + /// Index 1 start + /// </summary> + public uint Index1; + + /// <summary> + /// End of track + 1 + /// </summary> + public uint EndOfTrack; + } + + struct NeroV1Dao + { + /// <summary> + /// "DAOI" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size (big endian) + /// </summary> + public uint ChunkSizeBe; + + /// <summary> + /// Chunk size (little endian) + /// </summary> + public uint ChunkSizeLe; + + /// <summary> + /// UPC (14 bytes, null-padded) + /// </summary> + public byte[] Upc; + + /// <summary> + /// TOC type + /// </summary> + public ushort TocType; + + /// <summary> + /// First track + /// </summary> + public byte FirstTrack; + + /// <summary> + /// Last track + /// </summary> + public byte LastTrack; + + /// <summary> + /// Tracks + /// </summary> + public List<NeroV1DaoEntry> Tracks; + } + + struct NeroV2DaoEntry + { + /// <summary> + /// ISRC (12 bytes) + /// </summary> + public byte[] Isrc; + + /// <summary> + /// Size of sector inside image (in bytes) + /// </summary> + public ushort SectorSize; + + /// <summary> + /// Sector mode in image + /// </summary> + public ushort Mode; + + /// <summary> + /// Seems to be always 0. + /// </summary> + public ushort Unknown; + + /// <summary> + /// Index 0 start + /// </summary> + public ulong Index0; + + /// <summary> + /// Index 1 start + /// </summary> + public ulong Index1; + + /// <summary> + /// End of track + 1 + /// </summary> + public ulong EndOfTrack; + } + + struct NeroV2Dao + { + /// <summary> + /// "DAOX" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size (big endian) + /// </summary> + public uint ChunkSizeBe; + + /// <summary> + /// Chunk size (little endian) + /// </summary> + public uint ChunkSizeLe; + + /// <summary> + /// UPC (14 bytes, null-padded) + /// </summary> + public byte[] Upc; + + /// <summary> + /// TOC type + /// </summary> + public ushort TocType; + + /// <summary> + /// First track + /// </summary> + public byte FirstTrack; + + /// <summary> + /// Last track + /// </summary> + public byte LastTrack; + + /// <summary> + /// Tracks + /// </summary> + public List<NeroV2DaoEntry> Tracks; + } + + struct NeroCdTextPack + { + /// <summary> + /// Pack type + /// </summary> + public byte PackType; + + /// <summary> + /// Track number + /// </summary> + public byte TrackNumber; + + /// <summary> + /// Pack number in block + /// </summary> + public byte PackNumber; + + /// <summary> + /// Block number + /// </summary> + public byte BlockNumber; + + /// <summary> + /// 12 bytes of data + /// </summary> + public byte[] Text; + + /// <summary> + /// CRC + /// </summary> + public ushort Crc; + } + + struct NeroCdText + { + /// <summary> + /// "CDTX" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// CD-TEXT packs + /// </summary> + public List<NeroCdTextPack> Packs; + } + + struct NeroV1TaoEntry + { + /// <summary> + /// Offset of track on image + /// </summary> + public uint Offset; + + /// <summary> + /// Length of track in bytes + /// </summary> + public uint Length; + + /// <summary> + /// Track mode + /// </summary> + public uint Mode; + + /// <summary> + /// LBA track start (plus 150 lead in sectors) + /// </summary> + public uint StartLba; + + /// <summary> + /// Unknown + /// </summary> + public uint Unknown; + } + + struct NeroV1Tao + { + /// <summary> + /// "ETNF" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// CD-TEXT packs + /// </summary> + public List<NeroV1TaoEntry> Tracks; + } + + struct NeroV2TaoEntry + { + /// <summary> + /// Offset of track on image + /// </summary> + public ulong Offset; + + /// <summary> + /// Length of track in bytes + /// </summary> + public ulong Length; + + /// <summary> + /// Track mode + /// </summary> + public uint Mode; + + /// <summary> + /// LBA track start (plus 150 lead in sectors) + /// </summary> + public uint StartLba; + + /// <summary> + /// Unknown + /// </summary> + public uint Unknown; + + /// <summary> + /// Track length in sectors + /// </summary> + public uint Sectors; + } + + struct NeroV2Tao + { + /// <summary> + /// "ETN2" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// CD-TEXT packs + /// </summary> + public List<NeroV2TaoEntry> Tracks; + } + + struct NeroSession + { + /// <summary> + /// "SINF" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Tracks in session + /// </summary> + public uint Tracks; + } + + struct NeroMediaType + { + /// <summary> + /// "MTYP" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Media type + /// </summary> + public uint Type; + } + + struct NeroDiscInformation + { + /// <summary> + /// "DINF" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Unknown + /// </summary> + public uint Unknown; + } + + struct NeroTocChunk + { + /// <summary> + /// "TOCT" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Unknown + /// </summary> + public ushort Unknown; + } + + struct NeroReloChunk + { + /// <summary> + /// "RELO" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + + /// <summary> + /// Unknown + /// </summary> + public uint Unknown; + } + + struct NeroEndOfChunkChain + { + /// <summary> + /// "END!" + /// </summary> + public uint ChunkId; + + /// <summary> + /// Chunk size + /// </summary> + public uint ChunkSize; + } + + // Internal use only + struct NeroTrack + { + public byte[] Isrc; + public ushort SectorSize; + public ulong Offset; + public ulong Length; + public ulong EndOfTrack; + public uint Mode; + public ulong StartLba; + public ulong Sectors; + public ulong Index0; + public ulong Index1; + public uint Sequence; + } + + enum DaoMode : ushort + { + Data = 0x0000, + DataM2F1 = 0x0002, + DataM2F2 = 0x0003, + DataRaw = 0x0005, + DataM2Raw = 0x0006, + Audio = 0x0007, + DataRawSub = 0x000F, + AudioSub = 0x0010, + DataM2RawSub = 0x0011 + } + + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum NeroMediaTypes : uint + { + /// <summary> + /// No media + /// </summary> + NeroMtypNone = 0x00000, + /// <summary> + /// CD-R/RW + /// </summary> + NeroMtypCd = 0x00001, + /// <summary> + /// DDCD-R/RW + /// </summary> + NeroMtypDdcd = 0x00002, + /// <summary> + /// DVD-R/RW + /// </summary> + NeroMtypDvdM = 0x00004, + /// <summary> + /// DVD+RW + /// </summary> + NeroMtypDvdP = 0x00008, + /// <summary> + /// DVD-RAM + /// </summary> + NeroMtypDvdRam = 0x00010, + /// <summary> + /// Multi-level disc + /// </summary> + NeroMtypMl = 0x00020, + /// <summary> + /// Mount Rainier + /// </summary> + NeroMtypMrw = 0x00040, + /// <summary> + /// Exclude CD-R + /// </summary> + NeroMtypNoCdr = 0x00080, + /// <summary> + /// Exclude CD-RW + /// </summary> + NeroMtypNoCdrw = 0x00100, + /// <summary> + /// CD-RW + /// </summary> + NeroMtypCdrw = NeroMtypCd | NeroMtypNoCdr, + /// <summary> + /// CD-R + /// </summary> + NeroMtypCdr = NeroMtypCd | NeroMtypNoCdrw, + /// <summary> + /// DVD-ROM + /// </summary> + NeroMtypDvdRom = 0x00200, + /// <summary> + /// CD-ROM + /// </summary> + NeroMtypCdrom = 0x00400, + /// <summary> + /// Exclude DVD-RW + /// </summary> + NeroMtypNoDvdMRw = 0x00800, + /// <summary> + /// Exclude DVD-R + /// </summary> + NeroMtypNoDvdMR = 0x01000, + /// <summary> + /// Exclude DVD+RW + /// </summary> + NeroMtypNoDvdPRw = 0x02000, + /// <summary> + /// Exclude DVD+R + /// </summary> + NeroMtypNoDvdPR = 0x04000, + /// <summary> + /// DVD-R + /// </summary> + NeroMtypDvdMR = NeroMtypDvdM | NeroMtypNoDvdMRw, + /// <summary> + /// DVD-RW + /// </summary> + NeroMtypDvdMRw = NeroMtypDvdM | NeroMtypNoDvdMR, + /// <summary> + /// DVD+R + /// </summary> + NeroMtypDvdPR = NeroMtypDvdP | NeroMtypNoDvdPRw, + /// <summary> + /// DVD+RW + /// </summary> + NeroMtypDvdPRw = NeroMtypDvdP | NeroMtypNoDvdPR, + /// <summary> + /// Packet-writing (fixed) + /// </summary> + NeroMtypFpacket = 0x08000, + /// <summary> + /// Packet-writing (variable) + /// </summary> + NeroMtypVpacket = 0x10000, + /// <summary> + /// Packet-writing (any) + /// </summary> + NeroMtypPacketw = NeroMtypMrw | NeroMtypFpacket | NeroMtypVpacket, + /// <summary> + /// HD-Burn + /// </summary> + NeroMtypHdb = 0x20000, + /// <summary> + /// DVD+R DL + /// </summary> + NeroMtypDvdPR9 = 0x40000, + /// <summary> + /// DVD-R DL + /// </summary> + NeroMtypDvdMR9 = 0x80000, + /// <summary> + /// Any DVD double-layer + /// </summary> + NeroMtypDvdAnyR9 = NeroMtypDvdPR9 | NeroMtypDvdMR9, + /// <summary> + /// Any DVD + /// </summary> + NeroMtypDvdAny = NeroMtypDvdM | NeroMtypDvdP | NeroMtypDvdRam | NeroMtypDvdAnyR9, + /// <summary> + /// BD-ROM + /// </summary> + NeroMtypBdRom = 0x100000, + /// <summary> + /// BD-R + /// </summary> + NeroMtypBdR = 0x200000, + /// <summary> + /// BD-RE + /// </summary> + NeroMtypBdRe = 0x400000, + /// <summary> + /// BD-R/RE + /// </summary> + NeroMtypBd = NeroMtypBdR | NeroMtypBdRe, + /// <summary> + /// Any BD + /// </summary> + NeroMtypBdAny = NeroMtypBd | NeroMtypBdRom, + /// <summary> + /// HD DVD-ROM + /// </summary> + NeroMtypHdDvdRom = 0x0800000, + /// <summary> + /// HD DVD-R + /// </summary> + NeroMtypHdDvdR = 0x1000000, + /// <summary> + /// HD DVD-RW + /// </summary> + NeroMtypHdDvdRw = 0x2000000, + /// <summary> + /// HD DVD-R/RW + /// </summary> + NeroMtypHdDvd = NeroMtypHdDvdR | NeroMtypHdDvdRw, + /// <summary> + /// Any HD DVD + /// </summary> + NeroMtypHdDvdAny = NeroMtypHdDvd | NeroMtypHdDvdRom, + /// <summary> + /// Any DVD, old + /// </summary> + NeroMtypDvdAnyOld = NeroMtypDvdM | NeroMtypDvdP | NeroMtypDvdRam + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Parallels.cs b/DiscImageChef.DiscImages/Parallels.cs index 6c675030e..d0038bdba 100644 --- a/DiscImageChef.DiscImages/Parallels.cs +++ b/DiscImageChef.DiscImages/Parallels.cs @@ -43,86 +43,29 @@ namespace DiscImageChef.DiscImages { public class Parallels : ImagePlugin { - #region Internal constants - readonly byte[] parallelsMagic = - {0x57, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x46, 0x72, 0x65, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65}; - readonly byte[] parallelsExtMagic = - {0x57, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x46, 0x72, 0x65, 0x53, 0x70, 0x61, 0x63, 0x45, 0x78, 0x74}; - const uint PARALLELS_VERSION = 2; const uint PARALLELS_INUSE = 0x746F6E59; const uint PARALLELS_CLOSED = 0x312E3276; const uint PARALLELS_EMPTY = 0x00000001; - #endregion - - #region Internal Structures - /// <summary> - /// Parallels disk image header, little-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ParallelsHeader - { - /// <summary> - /// Magic, <see cref="Parallels.parallelsMagic"/> or <see cref="Parallels.parallelsExtMagic"/> - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] magic; - /// <summary> - /// Version - /// </summary> - public uint version; - /// <summary> - /// Disk geometry parameter - /// </summary> - public uint heads; - /// <summary> - /// Disk geometry parameter - /// </summary> - public uint cylinders; - /// <summary> - /// Cluser size in sectors - /// </summary> - public uint cluster_size; - /// <summary> - /// Entries in BAT (clusters in image) - /// </summary> - public uint bat_entries; - /// <summary> - /// Disk size in sectors - /// </summary> - public ulong sectors; - /// <summary> - /// Set to <see cref="Parallels.PARALLELS_INUSE"/> if image is opened by any software, <see cref="Parallels.PARALLELS_CLOSED"/> if not, and 0 if old version - /// </summary> - public uint in_use; - /// <summary> - /// Offset in sectors to start of data - /// </summary> - public uint data_off; - /// <summary> - /// Flags - /// </summary> - public uint flags; - /// <summary> - /// Offset in sectors to format extension - /// </summary> - public ulong ext_off; - } - #endregion - - bool extended; - ParallelsHeader pHdr; - uint[] bat; - long dataOffset; - uint clusterBytes; - bool empty; - Stream imageStream; - - Dictionary<ulong, byte[]> sectorCache; const uint MAX_CACHE_SIZE = 16777216; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + readonly byte[] parallelsExtMagic = + {0x57, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x46, 0x72, 0x65, 0x53, 0x70, 0x61, 0x63, 0x45, 0x78, 0x74}; + readonly byte[] parallelsMagic = + {0x57, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x46, 0x72, 0x65, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65}; + uint[] bat; + uint clusterBytes; + long dataOffset; + bool empty; + + bool extended; + Stream imageStream; + ParallelsHeader pHdr; + + Dictionary<ulong, byte[]> sectorCache; public Parallels() { @@ -357,7 +300,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -518,6 +460,58 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// Parallels disk image header, little-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ParallelsHeader + { + /// <summary> + /// Magic, <see cref="Parallels.parallelsMagic" /> or <see cref="Parallels.parallelsExtMagic" /> + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] magic; + /// <summary> + /// Version + /// </summary> + public uint version; + /// <summary> + /// Disk geometry parameter + /// </summary> + public uint heads; + /// <summary> + /// Disk geometry parameter + /// </summary> + public uint cylinders; + /// <summary> + /// Cluser size in sectors + /// </summary> + public uint cluster_size; + /// <summary> + /// Entries in BAT (clusters in image) + /// </summary> + public uint bat_entries; + /// <summary> + /// Disk size in sectors + /// </summary> + public ulong sectors; + /// <summary> + /// Set to <see cref="Parallels.PARALLELS_INUSE" /> if image is opened by any software, + /// <see cref="Parallels.PARALLELS_CLOSED" /> if not, and 0 if old version + /// </summary> + public uint in_use; + /// <summary> + /// Offset in sectors to start of data + /// </summary> + public uint data_off; + /// <summary> + /// Flags + /// </summary> + public uint flags; + /// <summary> + /// Offset in sectors to format extension + /// </summary> + public ulong ext_off; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/PartClone.cs b/DiscImageChef.DiscImages/PartClone.cs index 903121c00..c2e7407c7 100644 --- a/DiscImageChef.DiscImages/PartClone.cs +++ b/DiscImageChef.DiscImages/PartClone.cs @@ -44,73 +44,25 @@ namespace DiscImageChef.DiscImages { public class PartClone : ImagePlugin { - #region Internal constants - readonly byte[] partCloneMagic = - {0x70, 0x61, 0x72, 0x74, 0x63, 0x6C, 0x6F, 0x6E, 0x65, 0x2D, 0x69, 0x6D, 0x61, 0x67, 0x65}; - readonly byte[] biTmAgIc = {0x42, 0x69, 0x54, 0x6D, 0x41, 0x67, 0x49, 0x63}; const int CRC_SIZE = 4; - #endregion - - #region Internal Structures - /// <summary> - /// PartClone disk image header, little-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct PartCloneHeader - { - /// <summary> - /// Magic, <see cref="PartClone.partCloneMagic"/> - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] magic; - /// <summary> - /// Source filesystem - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] filesystem; - /// <summary> - /// Version - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] version; - /// <summary> - /// Padding - /// </summary> - public ushort padding; - /// <summary> - /// Block (sector) size - /// </summary> - public uint blockSize; - /// <summary> - /// Size of device containing the cloned partition - /// </summary> - public ulong deviceSize; - /// <summary> - /// Total blocks in cloned partition - /// </summary> - public ulong totalBlocks; - /// <summary> - /// Used blocks in cloned partition - /// </summary> - public ulong usedBlocks; - /// <summary> - /// Empty space - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] public byte[] buffer; - } - #endregion - - PartCloneHeader pHdr; - // The used block "bitmap" uses one byte per block - // TODO: Convert on-image bytemap to on-memory bitmap - byte[] byteMap; - Stream imageStream; - long dataOff; - - Dictionary<ulong, byte[]> sectorCache; const uint MAX_CACHE_SIZE = 16777216; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + readonly byte[] biTmAgIc = {0x42, 0x69, 0x54, 0x6D, 0x41, 0x67, 0x49, 0x63}; + readonly byte[] partCloneMagic = + {0x70, 0x61, 0x72, 0x74, 0x63, 0x6C, 0x6F, 0x6E, 0x65, 0x2D, 0x69, 0x6D, 0x61, 0x67, 0x65}; + // The used block "bitmap" uses one byte per block + // TODO: Convert on-image bytemap to on-memory bitmap + byte[] byteMap; + long dataOff; ExtentsULong extents; Dictionary<ulong, ulong> extentsOff; + Stream imageStream; + + PartCloneHeader pHdr; + + Dictionary<ulong, byte[]> sectorCache; public PartClone() { @@ -383,7 +335,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -545,6 +496,49 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// PartClone disk image header, little-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PartCloneHeader + { + /// <summary> + /// Magic, <see cref="PartClone.partCloneMagic" /> + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] magic; + /// <summary> + /// Source filesystem + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] public byte[] filesystem; + /// <summary> + /// Version + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] version; + /// <summary> + /// Padding + /// </summary> + public ushort padding; + /// <summary> + /// Block (sector) size + /// </summary> + public uint blockSize; + /// <summary> + /// Size of device containing the cloned partition + /// </summary> + public ulong deviceSize; + /// <summary> + /// Total blocks in cloned partition + /// </summary> + public ulong totalBlocks; + /// <summary> + /// Used blocks in cloned partition + /// </summary> + public ulong usedBlocks; + /// <summary> + /// Empty space + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] public byte[] buffer; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Partimage.cs b/DiscImageChef.DiscImages/Partimage.cs index d7d962fd1..208e17a87 100644 --- a/DiscImageChef.DiscImages/Partimage.cs +++ b/DiscImageChef.DiscImages/Partimage.cs @@ -39,18 +39,13 @@ using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.Filters; using Extents; + #pragma warning disable 649 namespace DiscImageChef.DiscImages { public class Partimage : ImagePlugin { - #region Internal constants - readonly byte[] partimageMagic = - { - 0x50, 0x61, 0x52, 0x74, 0x49, 0x6D, 0x41, 0x67, 0x45, 0x2D, 0x56, 0x6F, 0x4C, 0x75, 0x4D, 0x65, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; const int MAX_DESCRIPTION = 4096; const int MAX_HOSTNAMESIZE = 128; const int MAX_DEVICENAMELEN = 512; @@ -77,187 +72,25 @@ namespace DiscImageChef.DiscImages const string MAGIC_BEGIN_EXT008 = "MAGIC-BEGIN-EXT008"; // reserved for future use const string MAGIC_BEGIN_EXT009 = "MAGIC-BEGIN-EXT009"; // reserved for future use const string MAGIC_BEGIN_VOLUME = "PaRtImAgE-VoLuMe"; - #endregion - - #region Internal Structures - /// <summary> - /// Partimage disk image header, little-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct PartimageHeader - { - /// <summary> - /// Magic, <see cref="Partimage.partimageMagic"/> - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] magic; - /// <summary> - /// Source filesystem - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] version; - /// <summary> - /// Volume number - /// </summary> - public uint volumeNumber; - /// <summary> - /// Image identifier - /// </summary> - public ulong identificator; - /// <summary> - /// Empty space - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 404)] public byte[] reserved; - } - - struct PortableTm - { - public uint Second; - public uint Minute; - public uint Hour; - public uint DayOfMonth; - public uint Month; - public uint Year; - public uint DayOfWeek; - public uint DayOfYear; - public uint IsDst; - - public uint GmtOff; - public uint Timezone; - } - - enum PCompression : uint - { - None = 0, - Gzip = 1, - Bzip2 = 2, - Lzo = 3 - } - - enum PEncryption : uint - { - None = 0 - } - - /// <summary> - /// Partimage CMainHeader - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct PartimageMainHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] - public byte[] szFileSystem; // ext2fs, ntfs, reiserfs, ... - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DESCRIPTION)] - public byte[] szPartDescription; // user description of the partition - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICENAMELEN)] - public byte[] szOriginalDevice; // original partition name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4095)] - public byte[] szFirstImageFilepath; //MAXPATHLEN]; // for splitted image files - - // system and hardware infos - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameSysname; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameNodename; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameRelease; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameVersion; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameMachine; - - public PCompression dwCompression; // COMPRESS_XXXXXX - public uint dwMainFlags; - public PortableTm dateCreate; // date of image creation - public ulong qwPartSize; // size of the partition in bytes - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_HOSTNAMESIZE)] public byte[] szHostname; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] szVersion; // version of the image file - - // MBR backup - public uint dwMbrCount; // how many MBR are saved in the image file - public uint dwMbrSize; // size of a MBR record (allow to change the size in the next versions) - - // future encryption support - public PEncryption dwEncryptAlgo; // algo used to encrypt data - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] cHashTestKey; // used to test the password without giving it - - // reserved for future use (save DiskLabel, Extended partitions, ...) - public uint dwReservedFuture000; - public uint dwReservedFuture001; - public uint dwReservedFuture002; - public uint dwReservedFuture003; - public uint dwReservedFuture004; - public uint dwReservedFuture005; - public uint dwReservedFuture006; - public uint dwReservedFuture007; - public uint dwReservedFuture008; - public uint dwReservedFuture009; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6524)] - public byte[] cReserved; // Adjust to fit with total header size - - public uint crc; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CMbr // must be 1024 - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MBR_SIZE_WHOLE)] public byte[] cData; - public uint dwDataCRC; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICENAMELEN)] public byte[] szDevice; // ex: "hda" - - // disk identificators - ulong qwBlocksCount; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DESC_MODEL)] public byte[] szDescModel; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 884)] public byte[] cReserved; // for future use - - //public byte[] szDescGeometry[MAX_DESC_GEOMETRY]; - //public byte[] szDescIdentify[MAX_DESC_IDENTIFY]; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CCheck - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] byte[] cMagic; // must be 'C','H','K' - public uint dwCRC; // CRC of the CHECK_FREQUENCY blocks - public ulong qwPos; // number of the last block written - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CLocalHeader // size must be 16384 (adjust the reserved data) - { - public ulong qwBlockSize; - public ulong qwUsedBlocks; - public ulong qwBlocksCount; - public ulong qwBitmapSize; // bytes in the bitmap - public ulong qwBadBlocksCount; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] szLabel; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16280)] - public byte[] cReserved; // Adjust to fit with total header size - - public uint crc; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct CMainTail // size must be 16384 (adjust the reserved data) - { - public ulong qwCRC; - public uint dwVolumeNumber; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16372)] - public byte[] cReserved; // Adjust to fit with total header size - } - #endregion - - PartimageHeader cVolumeHeader; - PartimageMainHeader cMainHeader; - byte[] bitmap; - Stream imageStream; - long dataOff; - - Dictionary<ulong, byte[]> sectorCache; const uint MAX_CACHE_SIZE = 16777216; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + readonly byte[] partimageMagic = + { + 0x50, 0x61, 0x52, 0x74, 0x49, 0x6D, 0x41, 0x67, 0x45, 0x2D, 0x56, 0x6F, 0x4C, 0x75, 0x4D, 0x65, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + byte[] bitmap; + PartimageMainHeader cMainHeader; + + PartimageHeader cVolumeHeader; + long dataOff; ExtentsULong extents; Dictionary<ulong, ulong> extentsOff; + Stream imageStream; + + Dictionary<ulong, byte[]> sectorCache; public Partimage() { @@ -510,7 +343,7 @@ namespace DiscImageChef.DiscImages DateTime start = DateTime.Now; extents = new ExtentsULong(); extentsOff = new Dictionary<ulong, ulong>(); - bool current = (bitmap[0] & (1 << 0 % 8)) != 0; + bool current = (bitmap[0] & (1 << (0 % 8))) != 0; ulong blockOff = 0; ulong extentStart = 0; @@ -571,7 +404,8 @@ namespace DiscImageChef.DiscImages throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found"); - if((bitmap[sectorAddress / 8] & (1 << (int)(sectorAddress % 8))) == 0) return new byte[ImageInfo.SectorSize]; + if((bitmap[sectorAddress / 8] & (1 << (int)(sectorAddress % 8))) == 0) + return new byte[ImageInfo.SectorSize]; if(sectorCache.TryGetValue(sectorAddress, out byte[] sector)) return sector; @@ -701,7 +535,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -863,6 +696,169 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// Partimage disk image header, little-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PartimageHeader + { + /// <summary> + /// Magic, <see cref="Partimage.partimageMagic" /> + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] magic; + /// <summary> + /// Source filesystem + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] version; + /// <summary> + /// Volume number + /// </summary> + public uint volumeNumber; + /// <summary> + /// Image identifier + /// </summary> + public ulong identificator; + /// <summary> + /// Empty space + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 404)] public byte[] reserved; + } + + struct PortableTm + { + public uint Second; + public uint Minute; + public uint Hour; + public uint DayOfMonth; + public uint Month; + public uint Year; + public uint DayOfWeek; + public uint DayOfYear; + public uint IsDst; + + public uint GmtOff; + public uint Timezone; + } + + enum PCompression : uint + { + None = 0, + Gzip = 1, + Bzip2 = 2, + Lzo = 3 + } + + enum PEncryption : uint + { + None = 0 + } + + /// <summary> + /// Partimage CMainHeader + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PartimageMainHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] szFileSystem; // ext2fs, ntfs, reiserfs, ... + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DESCRIPTION)] + public byte[] szPartDescription; // user description of the partition + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICENAMELEN)] + public byte[] szOriginalDevice; // original partition name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4095)] + public byte[] szFirstImageFilepath; //MAXPATHLEN]; // for splitted image files + + // system and hardware infos + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameSysname; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameNodename; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameRelease; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameVersion; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_UNAMEINFOLEN)] public byte[] szUnameMachine; + + public PCompression dwCompression; // COMPRESS_XXXXXX + public uint dwMainFlags; + public PortableTm dateCreate; // date of image creation + public ulong qwPartSize; // size of the partition in bytes + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_HOSTNAMESIZE)] public byte[] szHostname; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] szVersion; // version of the image file + + // MBR backup + public uint dwMbrCount; // how many MBR are saved in the image file + public uint dwMbrSize; // size of a MBR record (allow to change the size in the next versions) + + // future encryption support + public PEncryption dwEncryptAlgo; // algo used to encrypt data + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] cHashTestKey; // used to test the password without giving it + + // reserved for future use (save DiskLabel, Extended partitions, ...) + public uint dwReservedFuture000; + public uint dwReservedFuture001; + public uint dwReservedFuture002; + public uint dwReservedFuture003; + public uint dwReservedFuture004; + public uint dwReservedFuture005; + public uint dwReservedFuture006; + public uint dwReservedFuture007; + public uint dwReservedFuture008; + public uint dwReservedFuture009; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6524)] + public byte[] cReserved; // Adjust to fit with total header size + + public uint crc; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CMbr // must be 1024 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MBR_SIZE_WHOLE)] public byte[] cData; + public uint dwDataCRC; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICENAMELEN)] public byte[] szDevice; // ex: "hda" + + // disk identificators + ulong qwBlocksCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DESC_MODEL)] public byte[] szDescModel; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 884)] public byte[] cReserved; // for future use + + //public byte[] szDescGeometry[MAX_DESC_GEOMETRY]; + //public byte[] szDescIdentify[MAX_DESC_IDENTIFY]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CCheck + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] byte[] cMagic; // must be 'C','H','K' + public uint dwCRC; // CRC of the CHECK_FREQUENCY blocks + public ulong qwPos; // number of the last block written + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CLocalHeader // size must be 16384 (adjust the reserved data) + { + public ulong qwBlockSize; + public ulong qwUsedBlocks; + public ulong qwBlocksCount; + public ulong qwBitmapSize; // bytes in the bitmap + public ulong qwBadBlocksCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] szLabel; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16280)] + public byte[] cReserved; // Adjust to fit with total header size + + public uint crc; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CMainTail // size must be 16384 (adjust the reserved data) + { + public ulong qwCRC; + public uint dwVolumeNumber; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16372)] + public byte[] cReserved; // Adjust to fit with total header size + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/QCOW.cs b/DiscImageChef.DiscImages/QCOW.cs index 28e087b87..499c132b1 100644 --- a/DiscImageChef.DiscImages/QCOW.cs +++ b/DiscImageChef.DiscImages/QCOW.cs @@ -44,9 +44,8 @@ namespace DiscImageChef.DiscImages { public class Qcow : ImagePlugin { - #region Internal constants /// <summary> - /// Magic number: 'Q', 'F', 'I', 0xFB + /// Magic number: 'Q', 'F', 'I', 0xFB /// </summary> const uint QCOW_MAGIC = 0x514649FB; const uint QCOW_VERSION = 1; @@ -55,83 +54,28 @@ namespace DiscImageChef.DiscImages const ulong QCOW_COMPRESSED = 0x8000000000000000; const int MAX_CACHE_SIZE = 16777216; - #endregion - #region Internal Structures - /// <summary> - /// QCOW header, big-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct QCowHeader - { - /// <summary> - /// <see cref="Qcow.QCOW_MAGIC"/> - /// </summary> - public uint magic; - /// <summary> - /// Must be 1 - /// </summary> - public uint version; - /// <summary> - /// Offset inside file to string containing backing file - /// </summary> - public ulong backing_file_offset; - /// <summary> - /// Size of <see cref="backing_file_offset"/> - /// </summary> - public uint backing_file_size; - /// <summary> - /// Modification time - /// </summary> - public uint mtime; - /// <summary> - /// Size in bytes - /// </summary> - public ulong size; - /// <summary> - /// Cluster bits - /// </summary> - public byte cluster_bits; - /// <summary> - /// L2 table bits - /// </summary> - public byte l2_bits; - /// <summary> - /// Padding - /// </summary> - public ushort padding; - /// <summary> - /// Encryption method - /// </summary> - public uint crypt_method; - /// <summary> - /// Offset to L1 table - /// </summary> - public ulong l1_table_offset; - } - #endregion - - QCowHeader qHdr; - int clusterSize; + const int MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + Dictionary<ulong, byte[]> clusterCache; int clusterSectors; - uint l1Size; - int l2Size; - ulong[] l1Table; + int clusterSize; + + Stream imageStream; ulong l1Mask; int l1Shift; + uint l1Size; + ulong[] l1Table; ulong l2Mask; - ulong sectorMask; + int l2Size; + Dictionary<ulong, ulong[]> l2TableCache; + int maxClusterCache; + int maxL2TableCache; + + QCowHeader qHdr; Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> clusterCache; - Dictionary<ulong, ulong[]> l2TableCache; - - int maxCachedSectors = MAX_CACHE_SIZE / 512; - int maxL2TableCache; - int maxClusterCache; - - Stream imageStream; + ulong sectorMask; public Qcow() { @@ -281,7 +225,9 @@ namespace DiscImageChef.DiscImages clusterCache = new Dictionary<ulong, byte[]>(); ImageInfo.ImageCreationTime = imageFilter.GetCreationTime(); - ImageInfo.ImageLastModificationTime = qHdr.mtime > 0 ? DateHandlers.UnixUnsignedToDateTime(qHdr.mtime) : imageFilter.GetLastWriteTime(); + ImageInfo.ImageLastModificationTime = qHdr.mtime > 0 + ? DateHandlers.UnixUnsignedToDateTime(qHdr.mtime) + : imageFilter.GetLastWriteTime(); ImageInfo.ImageName = Path.GetFileNameWithoutExtension(imageFilter.GetFilename()); ImageInfo.Sectors = qHdr.size / 512; ImageInfo.SectorSize = 512; @@ -381,7 +327,7 @@ namespace DiscImageChef.DiscImages Array.Copy(cluster, (int)(byteAddress & sectorMask), sector, 0, 512); } - if(sectorCache.Count >= maxCachedSectors) sectorCache.Clear(); + if(sectorCache.Count >= MAX_CACHED_SECTORS) sectorCache.Clear(); sectorCache.Add(sectorAddress, sector); @@ -478,7 +424,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -639,6 +584,57 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// QCOW header, big-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QCowHeader + { + /// <summary> + /// <see cref="Qcow.QCOW_MAGIC" /> + /// </summary> + public uint magic; + /// <summary> + /// Must be 1 + /// </summary> + public uint version; + /// <summary> + /// Offset inside file to string containing backing file + /// </summary> + public ulong backing_file_offset; + /// <summary> + /// Size of <see cref="backing_file_offset" /> + /// </summary> + public uint backing_file_size; + /// <summary> + /// Modification time + /// </summary> + public uint mtime; + /// <summary> + /// Size in bytes + /// </summary> + public ulong size; + /// <summary> + /// Cluster bits + /// </summary> + public byte cluster_bits; + /// <summary> + /// L2 table bits + /// </summary> + public byte l2_bits; + /// <summary> + /// Padding + /// </summary> + public ushort padding; + /// <summary> + /// Encryption method + /// </summary> + public uint crypt_method; + /// <summary> + /// Offset to L1 table + /// </summary> + public ulong l1_table_offset; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/QCOW2.cs b/DiscImageChef.DiscImages/QCOW2.cs index 9fa8154a8..32977e988 100644 --- a/DiscImageChef.DiscImages/QCOW2.cs +++ b/DiscImageChef.DiscImages/QCOW2.cs @@ -44,9 +44,8 @@ namespace DiscImageChef.DiscImages { public class Qcow2 : ImagePlugin { - #region Internal constants /// <summary> - /// Magic number: 'Q', 'F', 'I', 0xFB + /// Magic number: 'Q', 'F', 'I', 0xFB /// </summary> const uint QCOW_MAGIC = 0x514649FB; const uint QCOW_VERSION2 = 2; @@ -70,98 +69,28 @@ namespace DiscImageChef.DiscImages const ulong QCOW_HEADER_EXTENSION_BITMAPS = 0x23852875; const int MAX_CACHE_SIZE = 16777216; - #endregion - #region Internal Structures - /// <summary> - /// QCOW header, big-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct QCow2Header - { - /// <summary> - /// <see cref="Qcow2.QCOW_MAGIC"/> - /// </summary> - public uint magic; - /// <summary> - /// Must be 1 - /// </summary> - public uint version; - /// <summary> - /// Offset inside file to string containing backing file - /// </summary> - public ulong backing_file_offset; - /// <summary> - /// Size of <see cref="backing_file_offset"/> - /// </summary> - public uint backing_file_size; - /// <summary> - /// Cluster bits - /// </summary> - public uint cluster_bits; - /// <summary> - /// Size in bytes - /// </summary> - public ulong size; - /// <summary> - /// Encryption method - /// </summary> - public uint crypt_method; - /// <summary> - /// Size of L1 table - /// </summary> - public uint l1_size; - /// <summary> - /// Offset to L1 table - /// </summary> - public ulong l1_table_offset; - /// <summary> - /// Offset to reference count table - /// </summary> - public ulong refcount_table_offset; - /// <summary> - /// How many clusters does the refcount table span - /// </summary> - public uint refcount_table_clusters; - /// <summary> - /// Number of snapshots - /// </summary> - public uint nb_snapshots; - /// <summary> - /// Offset to QCowSnapshotHeader - /// </summary> - public ulong snapshots_offset; - - // Added in version 3 - public ulong features; - public ulong compat_features; - public ulong autoclear_features; - public uint refcount_order; - public uint header_length; - } - #endregion - - QCow2Header qHdr; - int clusterSize; + const int MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + Dictionary<ulong, byte[]> clusterCache; int clusterSectors; - int l2Bits; - int l2Size; - ulong[] l1Table; + int clusterSize; + + Stream imageStream; ulong l1Mask; int l1Shift; + ulong[] l1Table; + int l2Bits; ulong l2Mask; - ulong sectorMask; + int l2Size; + Dictionary<ulong, ulong[]> l2TableCache; + int maxClusterCache; + int maxL2TableCache; + + QCow2Header qHdr; Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> clusterCache; - Dictionary<ulong, ulong[]> l2TableCache; - - const int MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; - int maxL2TableCache; - int maxClusterCache; - - Stream imageStream; + ulong sectorMask; public Qcow2() { @@ -526,7 +455,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -687,6 +615,72 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// QCOW header, big-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QCow2Header + { + /// <summary> + /// <see cref="Qcow2.QCOW_MAGIC" /> + /// </summary> + public uint magic; + /// <summary> + /// Must be 1 + /// </summary> + public uint version; + /// <summary> + /// Offset inside file to string containing backing file + /// </summary> + public ulong backing_file_offset; + /// <summary> + /// Size of <see cref="backing_file_offset" /> + /// </summary> + public uint backing_file_size; + /// <summary> + /// Cluster bits + /// </summary> + public uint cluster_bits; + /// <summary> + /// Size in bytes + /// </summary> + public ulong size; + /// <summary> + /// Encryption method + /// </summary> + public uint crypt_method; + /// <summary> + /// Size of L1 table + /// </summary> + public uint l1_size; + /// <summary> + /// Offset to L1 table + /// </summary> + public ulong l1_table_offset; + /// <summary> + /// Offset to reference count table + /// </summary> + public ulong refcount_table_offset; + /// <summary> + /// How many clusters does the refcount table span + /// </summary> + public uint refcount_table_clusters; + /// <summary> + /// Number of snapshots + /// </summary> + public uint nb_snapshots; + /// <summary> + /// Offset to QCowSnapshotHeader + /// </summary> + public ulong snapshots_offset; + + // Added in version 3 + public ulong features; + public ulong compat_features; + public ulong autoclear_features; + public uint refcount_order; + public uint header_length; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/QED.cs b/DiscImageChef.DiscImages/QED.cs index c7ec19462..30681350f 100644 --- a/DiscImageChef.DiscImages/QED.cs +++ b/DiscImageChef.DiscImages/QED.cs @@ -42,107 +42,52 @@ namespace DiscImageChef.DiscImages { public class Qed : ImagePlugin { - #region Internal constants /// <summary> - /// Magic number: 'Q', 'E', 'D', 0x00 + /// Magic number: 'Q', 'E', 'D', 0x00 /// </summary> const uint QED_MAGIC = 0x00444551; /// <summary> - /// Mask of unsupported incompatible features + /// Mask of unsupported incompatible features /// </summary> const ulong QED_FEATURE_MASK = 0xFFFFFFFFFFFFFFF8; /// <summary> - /// File is differential (has a backing file) + /// File is differential (has a backing file) /// </summary> const ulong QED_FEATURE_BACKING_FILE = 0x01; /// <summary> - /// Image needs a consistency check before writing + /// Image needs a consistency check before writing /// </summary> const ulong QED_FEATURE_NEEDS_CHECK = 0x02; - /// <summary>s - /// Backing file is a raw disk image + /// <summary> + /// s + /// Backing file is a raw disk image /// </summary> const ulong QED_FEATURE_RAW_BACKING = 0x04; const int MAX_CACHE_SIZE = 16777216; - #endregion - #region Internal Structures - /// <summary> - /// QED header, big-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct QedHeader - { - /// <summary> - /// <see cref="Qed.QED_MAGIC"/> - /// </summary> - public uint magic; - /// <summary> - /// Cluster size in bytes - /// </summary> - public uint cluster_size; - /// <summary> - /// L1 and L2 table size in cluster - /// </summary> - public uint table_size; - /// <summary> - /// Header size in clusters - /// </summary> - public uint header_size; - /// <summary> - /// Incompatible features - /// </summary> - public ulong features; - /// <summary> - /// Compatible features - /// </summary> - public ulong compat_features; - /// <summary> - /// Self-resetting features - /// </summary> - public ulong autoclear_features; - /// <summary> - /// Offset to L1 table - /// </summary> - public ulong l1_table_offset; - /// <summary> - /// Image size - /// </summary> - public ulong image_size; - /// <summary> - /// Offset inside file to string containing backing file - /// </summary> - public ulong backing_file_offset; - /// <summary> - /// Size of <see cref="backing_file_offset"/> - /// </summary> - public uint backing_file_size; - } - #endregion - - QedHeader qHdr; + const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + int clusterBits; + Dictionary<ulong, byte[]> clusterCache; uint clusterSectors; - uint tableSize; - ulong[] l1Table; + + Stream imageStream; ulong l1Mask; int l1Shift; + ulong[] l1Table; ulong l2Mask; - ulong sectorMask; - int clusterBits; + Dictionary<ulong, ulong[]> l2TableCache; + uint maxClusterCache; + uint maxL2TableCache; + + QedHeader qHdr; Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> clusterCache; - Dictionary<ulong, ulong[]> l2TableCache; - - const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; - uint maxL2TableCache; - uint maxClusterCache; - - Stream imageStream; + ulong sectorMask; + uint tableSize; public Qed() { @@ -330,8 +275,7 @@ namespace DiscImageChef.DiscImages byte[] l2TableB = new byte[tableSize * 8]; imageStream.Read(l2TableB, 0, (int)tableSize * 8); DicConsole.DebugWriteLine("QED plugin", "Reading L2 table #{0}", l1Off); - for(long i = 0; i < l2Table.LongLength; i++) - l2Table[i] = BitConverter.ToUInt64(l2TableB, (int)(i * 8)); + for(long i = 0; i < l2Table.LongLength; i++) l2Table[i] = BitConverter.ToUInt64(l2TableB, (int)(i * 8)); if(l2TableCache.Count >= maxL2TableCache) l2TableCache.Clear(); @@ -457,7 +401,7 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - bool IsPowerOfTwo(uint x) + static bool IsPowerOfTwo(uint x) { while((x & 1) == 0 && x > 1) x >>= 1; @@ -497,7 +441,6 @@ namespace DiscImageChef.DiscImages return cnt; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -658,6 +601,57 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// QED header, big-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QedHeader + { + /// <summary> + /// <see cref="Qed.QED_MAGIC" /> + /// </summary> + public uint magic; + /// <summary> + /// Cluster size in bytes + /// </summary> + public uint cluster_size; + /// <summary> + /// L1 and L2 table size in cluster + /// </summary> + public uint table_size; + /// <summary> + /// Header size in clusters + /// </summary> + public uint header_size; + /// <summary> + /// Incompatible features + /// </summary> + public ulong features; + /// <summary> + /// Compatible features + /// </summary> + public ulong compat_features; + /// <summary> + /// Self-resetting features + /// </summary> + public ulong autoclear_features; + /// <summary> + /// Offset to L1 table + /// </summary> + public ulong l1_table_offset; + /// <summary> + /// Image size + /// </summary> + public ulong image_size; + /// <summary> + /// Offset inside file to string containing backing file + /// </summary> + public ulong backing_file_offset; + /// <summary> + /// Size of <see cref="backing_file_offset" /> + /// </summary> + public uint backing_file_size; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/RayDIM.cs b/DiscImageChef.DiscImages/RayDIM.cs index 135f3ac83..f5965c0e8 100644 --- a/DiscImageChef.DiscImages/RayDIM.cs +++ b/DiscImageChef.DiscImages/RayDIM.cs @@ -44,35 +44,11 @@ namespace DiscImageChef.DiscImages { public class RayDim : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct RayHdr - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] public byte[] signature; - public RayDiskTypes diskType; - public byte cylinders; - public byte sectorsPerTrack; - public byte heads; - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - enum RayDiskTypes : byte - { - Md2dd = 1, - Md2hd = 2, - Mf2dd = 3, - Mf2hd = 4, - Mf2ed = 5 - } - #endregion - - const string DIM_SIGNATURE_REGEX = + const string REGEX_SIGNATURE = "Disk IMage VER (?<major>\\d).(?<minor>\\d) Copyright \\(C\\) (?<year>\\d{4}) Ray Arachelian, All Rights Reserved\\." ; - #region Internal variables MemoryStream disk; - #endregion public RayDim() { @@ -125,7 +101,7 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("Ray Arachelian's Disk IMage plugin", "header.sectorsPerTrack = {0}", header.sectorsPerTrack); - Regex sx = new Regex(DIM_SIGNATURE_REGEX); + Regex sx = new Regex(REGEX_SIGNATURE); Match sm = sx.Match(signature); DicConsole.DebugWriteLine("Ray Arachelian's Disk IMage plugin", "header.signature matches? = {0}", @@ -151,7 +127,7 @@ namespace DiscImageChef.DiscImages string signature = StringHandlers.CToString(header.signature); - Regex sx = new Regex(DIM_SIGNATURE_REGEX); + Regex sx = new Regex(REGEX_SIGNATURE); Match sm = sx.Match(signature); if(!sm.Success) return false; @@ -369,7 +345,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -489,6 +464,25 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RayHdr + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] public byte[] signature; + public RayDiskTypes diskType; + public byte cylinders; + public byte sectorsPerTrack; + public byte heads; + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + enum RayDiskTypes : byte + { + Md2dd = 1, + Md2hd = 2, + Mf2dd = 3, + Mf2hd = 4, + Mf2ed = 5 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/RsIde.cs b/DiscImageChef.DiscImages/RsIde.cs index efae09349..d10a6f52b 100644 --- a/DiscImageChef.DiscImages/RsIde.cs +++ b/DiscImageChef.DiscImages/RsIde.cs @@ -43,6 +43,12 @@ namespace DiscImageChef.DiscImages { public class RsIde : ImagePlugin { + readonly byte[] signature = {0x52, 0x53, 0x2D, 0x49, 0x44, 0x45, 0x1A}; + ushort dataOff; + byte[] identify; + + Filter rsIdeImageFilter; + public RsIde() { Name = "RS-IDE Hard Disk Image"; @@ -72,28 +78,6 @@ namespace DiscImageChef.DiscImages }; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct RsIdeHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] public byte[] magic; - public byte revision; - public RsIdeFlags flags; - public ushort dataOff; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] reserved; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 106)] public byte[] identify; - } - - [Flags] - enum RsIdeFlags : byte - { - HalfSectors = 1 - } - - Filter rsIdeImageFilter; - ushort dataOff; - readonly byte[] signature = {0x52, 0x53, 0x2D, 0x49, 0x44, 0x45, 0x1A}; - byte[] identify; - public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -258,7 +242,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { if(!ImageInfo.ReadableMediaTags.Contains(tag) || tag != MediaTagType.ATA_IDENTIFY) @@ -424,6 +407,22 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RsIdeHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] public byte[] magic; + public byte revision; + public RsIdeFlags flags; + public ushort dataOff; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] reserved; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 106)] public byte[] identify; + } + + [Flags] + enum RsIdeFlags : byte + { + HalfSectors = 1 + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/SaveDskF.cs b/DiscImageChef.DiscImages/SaveDskF.cs index 984b08050..b34d172ac 100644 --- a/DiscImageChef.DiscImages/SaveDskF.cs +++ b/DiscImageChef.DiscImages/SaveDskF.cs @@ -43,65 +43,13 @@ namespace DiscImageChef.DiscImages { public class SaveDskF : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SaveDskFHeader - { - /// <summary>0x00 magic number</summary> - public ushort magic; - /// <summary>0x02 media type from FAT</summary> - public ushort mediaType; - /// <summary>0x04 bytes per sector</summary> - public ushort sectorSize; - /// <summary>0x06 sectors per cluster - 1</summary> - public byte clusterMask; - /// <summary>0x07 log2(cluster / sector)</summary> - public byte clusterShift; - /// <summary>0x08 reserved sectors</summary> - public ushort reservedSectors; - /// <summary>0x0A copies of FAT</summary> - public byte fatCopies; - /// <summary>0x0B entries in root directory</summary> - public ushort rootEntries; - /// <summary>0x0D first cluster</summary> - public ushort firstCluster; - /// <summary>0x0F clusters present in image</summary> - public ushort clustersCopied; - /// <summary>0x11 sectors per FAT</summary> - public byte sectorsPerFat; - /// <summary>0x12 sector number of root directory</summary> - public ushort rootDirectorySector; - /// <summary>0x14 sum of all image bytes</summary> - public uint checksum; - /// <summary>0x18 cylinders</summary> - public ushort cylinders; - /// <summary>0x1A heads</summary> - public ushort heads; - /// <summary>0x1C sectors per track</summary> - public ushort sectorsPerTrack; - /// <summary>0x1E always zero</summary> - public uint padding; - /// <summary>0x22 sectors present in image</summary> - public ushort sectorsCopied; - /// <summary>0x24 offset to comment</summary> - public ushort commentOffset; - /// <summary>0x26 offset to data</summary> - public ushort dataOffset; - } - #endregion Internal Structures - - #region Internal Constants const ushort SDF_MAGIC_OLD = 0x58AA; const ushort SDF_MAGIC = 0x59AA; const ushort SDF_MAGIC_COMPRESSED = 0x5AAA; - #endregion Internal Constants - - #region Internal variables - SaveDskFHeader header; - long sectors; uint calculatedChk; byte[] decodedDisk; - #endregion Internal variables + + SaveDskFHeader header; public SaveDskF() { @@ -132,7 +80,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -205,9 +152,6 @@ namespace DiscImageChef.DiscImages } while(b >= 0); - // In case there is omitted data - sectors = header.sectorsPerTrack * header.heads * header.cylinders; - DicConsole.DebugWriteLine("SaveDskF plugin", "Calculated checksum = 0x{0:X8}, {1}", calculatedChk, calculatedChk == header.checksum); @@ -514,9 +458,7 @@ namespace DiscImageChef.DiscImages { return ImageInfo.DriveSerialNumber; } - #endregion Public methods - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -596,6 +538,50 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SaveDskFHeader + { + /// <summary>0x00 magic number</summary> + public ushort magic; + /// <summary>0x02 media type from FAT</summary> + public ushort mediaType; + /// <summary>0x04 bytes per sector</summary> + public ushort sectorSize; + /// <summary>0x06 sectors per cluster - 1</summary> + public byte clusterMask; + /// <summary>0x07 log2(cluster / sector)</summary> + public byte clusterShift; + /// <summary>0x08 reserved sectors</summary> + public ushort reservedSectors; + /// <summary>0x0A copies of FAT</summary> + public byte fatCopies; + /// <summary>0x0B entries in root directory</summary> + public ushort rootEntries; + /// <summary>0x0D first cluster</summary> + public ushort firstCluster; + /// <summary>0x0F clusters present in image</summary> + public ushort clustersCopied; + /// <summary>0x11 sectors per FAT</summary> + public byte sectorsPerFat; + /// <summary>0x12 sector number of root directory</summary> + public ushort rootDirectorySector; + /// <summary>0x14 sum of all image bytes</summary> + public uint checksum; + /// <summary>0x18 cylinders</summary> + public ushort cylinders; + /// <summary>0x1A heads</summary> + public ushort heads; + /// <summary>0x1C sectors per track</summary> + public ushort sectorsPerTrack; + /// <summary>0x1E always zero</summary> + public uint padding; + /// <summary>0x22 sectors present in image</summary> + public ushort sectorsCopied; + /// <summary>0x24 offset to comment</summary> + public ushort commentOffset; + /// <summary>0x26 offset to data</summary> + public ushort dataOffset; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/SuperCardPro.cs b/DiscImageChef.DiscImages/SuperCardPro.cs index 7563b5f89..78b2b0ada 100644 --- a/DiscImageChef.DiscImages/SuperCardPro.cs +++ b/DiscImageChef.DiscImages/SuperCardPro.cs @@ -44,72 +44,6 @@ namespace DiscImageChef.DiscImages { public class SuperCardPro : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct ScpHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] signature; - public byte version; - public ScpDiskType type; - public byte revolutions; - public byte start; - public byte end; - public ScpFlags flags; - public byte bitCellEncoding; - public byte heads; - public byte reserved; - public uint checksum; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 168)] public uint[] offsets; - } - - public struct TrackHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] Signature; - public byte TrackNumber; - public TrackEntry[] Entries; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct TrackEntry - { - public uint indexTime; - public uint trackLength; - public uint dataOffset; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct ScpFooter - { - public uint manufacturerOffset; - public uint modelOffset; - public uint serialOffset; - public uint creatorOffset; - public uint applicationOffset; - public uint commentsOffset; - public long creationTime; - public long modificationTime; - public byte applicationVersion; - public byte hardwareVersion; - public byte firmwareVersion; - public byte imageVersion; - public uint signature; - } - #endregion Internal Structures - - #region Internal Constants - /// <summary> - /// SuperCardPro header signature: "SCP" - /// </summary> - readonly byte[] scpSignature = {0x53, 0x43, 0x50}; - /// <summary> - /// SuperCardPro track header signature: "TRK" - /// </summary> - readonly byte[] trkSignature = {0x54, 0x52, 0x4B}; - /// <summary> - /// SuperCardPro footer signature: "FPCS" - /// </summary> - const uint FOOTER_SIGNATURE = 0x53435046; - public enum ScpDiskType : byte { Commodore64 = 0x00, @@ -140,38 +74,49 @@ namespace DiscImageChef.DiscImages public enum ScpFlags : byte { /// <summary> - /// If set flux starts at index pulse + /// If set flux starts at index pulse /// </summary> Index = 0x00, /// <summary> - /// If set drive is 96tpi + /// If set drive is 96tpi /// </summary> Tpi = 0x02, /// <summary> - /// If set drive is 360rpm + /// If set drive is 360rpm /// </summary> Rpm = 0x04, /// <summary> - /// If set image contains normalized data + /// If set image contains normalized data /// </summary> Normalized = 0x08, /// <summary> - /// If set image is read/write capable + /// If set image is read/write capable /// </summary> Writable = 0x10, /// <summary> - /// If set, image has footer + /// If set, image has footer /// </summary> HasFooter = 0x20 } - #endregion Internal Constants - #region Internal variables + /// <summary> + /// SuperCardPro footer signature: "FPCS" + /// </summary> + const uint FOOTER_SIGNATURE = 0x53435046; + + /// <summary> + /// SuperCardPro header signature: "SCP" + /// </summary> + readonly byte[] scpSignature = {0x53, 0x43, 0x50}; + /// <summary> + /// SuperCardPro track header signature: "TRK" + /// </summary> + readonly byte[] trkSignature = {0x54, 0x52, 0x4B}; + // TODO: These variables have been made public so create-sidecar can access to this information until I define an API >4.0 public ScpHeader Header; - public Dictionary<byte, TrackHeader> Tracks; Stream scpStream; - #endregion Internal variables + public Dictionary<byte, TrackHeader> Tracks; public SuperCardPro() { @@ -202,7 +147,6 @@ namespace DiscImageChef.DiscImages }; } - #region Public methods public override bool IdentifyImage(Filter imageFilter) { Header = new ScpHeader(); @@ -369,9 +313,14 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageComments = \"{0}\"", ImageInfo.ImageComments); - ImageInfo.ImageCreationTime = footer.creationTime != 0 ? DateHandlers.UnixToDateTime(footer.creationTime) : imageFilter.GetCreationTime(); + ImageInfo.ImageCreationTime = footer.creationTime != 0 + ? DateHandlers.UnixToDateTime(footer.creationTime) + : imageFilter.GetCreationTime(); - ImageInfo.ImageLastModificationTime = footer.modificationTime != 0 ? DateHandlers.UnixToDateTime(footer.modificationTime) : imageFilter.GetLastWriteTime(); + ImageInfo.ImageLastModificationTime = + footer.modificationTime != 0 + ? DateHandlers.UnixToDateTime(footer.modificationTime) + : imageFilter.GetLastWriteTime(); DicConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreationTime = {0}", ImageInfo.ImageCreationTime); @@ -605,9 +554,7 @@ namespace DiscImageChef.DiscImages return Header.checksum == sum; } - #endregion Public methods - #region Unsupported features public override byte[] ReadSector(ulong sectorAddress, uint track) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -668,6 +615,55 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ScpHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] signature; + public byte version; + public ScpDiskType type; + public byte revolutions; + public byte start; + public byte end; + public ScpFlags flags; + public byte bitCellEncoding; + public byte heads; + public byte reserved; + public uint checksum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 168)] public uint[] offsets; + } + + public struct TrackHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] Signature; + public byte TrackNumber; + public TrackEntry[] Entries; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TrackEntry + { + public uint indexTime; + public uint trackLength; + public uint dataOffset; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ScpFooter + { + public uint manufacturerOffset; + public uint modelOffset; + public uint serialOffset; + public uint creatorOffset; + public uint applicationOffset; + public uint commentsOffset; + public long creationTime; + public long modificationTime; + public byte applicationVersion; + public byte hardwareVersion; + public byte firmwareVersion; + public byte imageVersion; + public uint signature; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/T98.cs b/DiscImageChef.DiscImages/T98.cs index 0c0d25090..96ea96190 100644 --- a/DiscImageChef.DiscImages/T98.cs +++ b/DiscImageChef.DiscImages/T98.cs @@ -41,6 +41,8 @@ namespace DiscImageChef.DiscImages { public class T98 : ImagePlugin { + Filter t98ImageFilter; + public T98() { Name = "T98 Hard Disk Image"; @@ -70,8 +72,6 @@ namespace DiscImageChef.DiscImages }; } - Filter t98ImageFilter; - public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -219,7 +219,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -380,6 +379,5 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/TeleDisk.cs b/DiscImageChef.DiscImages/TeleDisk.cs index 7ac013cf4..e76a1e65d 100644 --- a/DiscImageChef.DiscImages/TeleDisk.cs +++ b/DiscImageChef.DiscImages/TeleDisk.cs @@ -49,83 +49,6 @@ namespace DiscImageChef.DiscImages // http://www.classiccmp.org/dunfield/img54306/td0notes.txt public class TeleDisk : ImagePlugin { - #region Internal Structures - struct TeleDiskHeader - { - /// <summary>"TD" or "td" depending on compression</summary> - public ushort Signature; - /// <summary>Sequence, but TeleDisk seems to complaing if != 0</summary> - public byte Sequence; - /// <summary>Random, same byte for all disks in the same set</summary> - public byte DiskSet; - /// <summary>TeleDisk version, major in high nibble, minor in low nibble</summary> - public byte Version; - /// <summary>Data rate</summary> - public byte DataRate; - /// <summary>BIOS drive type</summary> - public byte DriveType; - /// <summary>Stepping used</summary> - public byte Stepping; - /// <summary>If set means image only allocates sectors marked in-use by FAT12</summary> - public byte DosAllocation; - /// <summary>Sides of disk</summary> - public byte Sides; - /// <summary>CRC of all the previous</summary> - public ushort Crc; - } - - struct TeleDiskCommentBlockHeader - { - /// <summary>CRC of comment block after crc field</summary> - public ushort Crc; - /// <summary>Length of comment</summary> - public ushort Length; - public byte Year; - public byte Month; - public byte Day; - public byte Hour; - public byte Minute; - public byte Second; - } - - struct TeleDiskTrackHeader - { - /// <summary>Sectors in the track, 0xFF if end of disk image (there is no spoon)</summary> - public byte Sectors; - /// <summary>Cylinder the head was on</summary> - public byte Cylinder; - /// <summary>Head/side used</summary> - public byte Head; - /// <summary>Lower byte of CRC of previous fields</summary> - public byte Crc; - } - - struct TeleDiskSectorHeader - { - /// <summary>Cylinder as stored on sector address mark</summary> - public byte Cylinder; - /// <summary>Head as stored on sector address mark</summary> - public byte Head; - /// <summary>Sector number as stored on sector address mark</summary> - public byte SectorNumber; - /// <summary>Sector size</summary> - public byte SectorSize; - /// <summary>Sector flags</summary> - public byte Flags; - /// <summary>Lower byte of TeleDisk CRC of sector header, data header and data block</summary> - public byte Crc; - } - - struct TeleDiskDataHeader - { - /// <summary>Size of all data (encoded) + next field (1)</summary> - public ushort DataSize; - /// <summary>Encoding used for data block</summary> - public byte DataEncoding; - } - #endregion - - #region Internal Constants // "TD" as little endian uint. const ushort TD_MAGIC = 0x4454; // "td" as little endian uint. Means whole file is compressed (aka Advanced Compression) @@ -185,21 +108,18 @@ namespace DiscImageChef.DiscImages const byte DATA_BLOCK_PATTERN = 0x01; // Data is encoded as RLE const byte DATA_BLOCK_RLE = 0x02; - #endregion - - #region Internal variables - TeleDiskHeader header; - TeleDiskCommentBlockHeader commentHeader; - byte[] commentBlock; - // LBA, data - uint totalDiskSize; bool aDiskCrcHasFailed; - List<ulong> sectorsWhereCrcHasFailed; - // Cylinder by head, sector data matrix - byte[][][][] sectorsData; + byte[] commentBlock; + TeleDiskCommentBlockHeader commentHeader; + + TeleDiskHeader header; Stream inStream; byte[] leadOut; - #endregion + // Cylinder by head, sector data matrix + byte[][][][] sectorsData; + List<ulong> sectorsWhereCrcHasFailed; + // LBA, data + uint totalDiskSize; public TeleDisk() { @@ -280,12 +200,10 @@ namespace DiscImageChef.DiscImages if(header.DataRate != DATA_RATE_250KBPS && header.DataRate != DATA_RATE_300KBPS && header.DataRate != DATA_RATE_500KBPS) return false; - if(header.DriveType != DRIVE_TYPE_35_DD && header.DriveType != DRIVE_TYPE_35_ED && - header.DriveType != DRIVE_TYPE_35_HD && header.DriveType != DRIVE_TYPE_525_DD && - header.DriveType != DRIVE_TYPE_525_HD && header.DriveType != DRIVE_TYPE_525_HD_DD_DISK && - header.DriveType != DRIVE_TYPE_8_INCH) return false; - - return true; + return header.DriveType == DRIVE_TYPE_35_DD || header.DriveType == DRIVE_TYPE_35_ED || + header.DriveType == DRIVE_TYPE_35_HD || header.DriveType == DRIVE_TYPE_525_DD || + header.DriveType == DRIVE_TYPE_525_HD || header.DriveType == DRIVE_TYPE_525_HD_DD_DISK || + header.DriveType == DRIVE_TYPE_8_INCH; } public override bool OpenImage(Filter imageFilter) @@ -416,7 +334,7 @@ namespace DiscImageChef.DiscImages aDiskCrcHasFailed |= cmtcrc != commentHeader.Crc; for(int i = 0; i < commentBlock.Length; i++) - // Replace NULLs, used by TeleDisk as newline markers, with UNIX newline marker + // Replace NULLs, used by TeleDisk as newline markers, with UNIX newline marker if(commentBlock[i] == 0x00) commentBlock[i] = 0x0A; ImageInfo.ImageComments = Encoding.ASCII.GetString(commentBlock); @@ -460,7 +378,6 @@ namespace DiscImageChef.DiscImages Crc = (byte)stream.ReadByte() }; - if(teleDiskTrack.Cylinder > totalCylinders) totalCylinders = teleDiskTrack.Cylinder; if(teleDiskTrack.Head > totalHeads) totalHeads = teleDiskTrack.Head; @@ -523,7 +440,6 @@ namespace DiscImageChef.DiscImages Crc = (byte)stream.ReadByte() }; - if(teleDiskTrack.Sectors == 0xFF) // End of disk image break; @@ -629,7 +545,8 @@ namespace DiscImageChef.DiscImages teleDiskSector.Crc = (byte)stream.ReadByte(); DicConsole.DebugWriteLine("TeleDisk plugin", "\tSector follows"); - DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark cylinder: {0}", teleDiskSector.Cylinder); + DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark cylinder: {0}", + teleDiskSector.Cylinder); DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark head: {0}", teleDiskSector.Head); DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tAddressMark sector number: {0}", teleDiskSector.SectorNumber); @@ -639,7 +556,8 @@ namespace DiscImageChef.DiscImages teleDiskSector.Crc); uint lba = (uint)(teleDiskSector.Cylinder * header.Sides * ImageInfo.SectorsPerTrack + - teleDiskSector.Head * ImageInfo.SectorsPerTrack + (teleDiskSector.SectorNumber - 1)); + teleDiskSector.Head * ImageInfo.SectorsPerTrack + + (teleDiskSector.SectorNumber - 1)); if((teleDiskSector.Flags & FLAGS_SECTOR_DATALESS) != FLAGS_SECTOR_DATALESS && (teleDiskSector.Flags & FLAGS_SECTOR_SKIPPED) != FLAGS_SECTOR_SKIPPED) { @@ -650,7 +568,8 @@ namespace DiscImageChef.DiscImages teleDiskData.DataEncoding = (byte)stream.ReadByte(); byte[] data = new byte[teleDiskData.DataSize]; stream.Read(data, 0, teleDiskData.DataSize); - DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tData size (in-image): {0}", teleDiskData.DataSize); + DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tData size (in-image): {0}", + teleDiskData.DataSize); DicConsole.DebugWriteLine("TeleDisk plugin", "\t\tData encoding: 0x{0:X2}", teleDiskData.DataEncoding); @@ -664,7 +583,8 @@ namespace DiscImageChef.DiscImages "Sector {0}:{3}:{4} calculated CRC 0x{1:X2} differs from stored CRC 0x{2:X2}", teleDiskTrack.Cylinder, tdSectorCalculatedCrc, teleDiskSector.Crc, teleDiskTrack.Cylinder, teleDiskSector.SectorNumber); - if((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) != FLAGS_SECTOR_NO_ID) sectorsWhereCrcHasFailed.Add(lba); + if((teleDiskSector.Flags & FLAGS_SECTOR_NO_ID) != FLAGS_SECTOR_NO_ID) + sectorsWhereCrcHasFailed.Add(lba); } } else decodedData = new byte[128 << teleDiskSector.SectorSize]; @@ -683,7 +603,8 @@ namespace DiscImageChef.DiscImages teleDiskSector.Head); else { - sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] = decodedData; + sectorsData[teleDiskTrack.Cylinder][teleDiskTrack.Head][teleDiskSector.SectorNumber] = + decodedData; totalDiskSize += (uint)decodedData.Length; } } @@ -880,7 +801,6 @@ namespace DiscImageChef.DiscImages return aDiskCrcHasFailed; } - #region Private methods static ushort TeleDiskCrc(ushort crc, byte[] buffer) { int counter = 0; @@ -925,8 +845,7 @@ namespace DiscImageChef.DiscImages case SECTOR_SIZE_8K: decodedData = new byte[8192]; break; - default: - throw new ImageNotSupportedException($"Sector size {sectorSize} is incorrect."); + default: throw new ImageNotSupportedException($"Sector size {sectorSize} is incorrect."); } switch(encodingType) @@ -1002,8 +921,7 @@ namespace DiscImageChef.DiscImages break; } - default: - throw new ImageNotSupportedException($"Data encoding {encodingType} is incorrect."); + default: throw new ImageNotSupportedException($"Data encoding {encodingType} is incorrect."); } return decodedData; @@ -1022,23 +940,24 @@ namespace DiscImageChef.DiscImages case 163840: { // Acorn disk uses 256 bytes/sector - if(ImageInfo.SectorSize == 256) return MediaType.ACORN_525_SS_DD_40; + return ImageInfo.SectorSize == 256 + ? MediaType.ACORN_525_SS_DD_40 + : MediaType.DOS_525_SS_DD_8; // DOS disks use 512 bytes/sector - return MediaType.DOS_525_SS_DD_8; } case 184320: { // Atari disk uses 256 bytes/sector - if(ImageInfo.SectorSize == 256) return MediaType.ATARI_525_DD; + return ImageInfo.SectorSize == 256 ? MediaType.ATARI_525_DD : MediaType.DOS_525_SS_DD_9; // DOS disks use 512 bytes/sector - return MediaType.DOS_525_SS_DD_9; } case 327680: { // Acorn disk uses 256 bytes/sector - if(ImageInfo.SectorSize == 256) return MediaType.ACORN_525_SS_DD_80; + return ImageInfo.SectorSize == 256 + ? MediaType.ACORN_525_SS_DD_80 + : MediaType.DOS_525_DS_DD_8; // DOS disks use 512 bytes/sector - return MediaType.DOS_525_DS_DD_8; } case 368640: return MediaType.DOS_525_DS_DD_9; case 1228800: return MediaType.DOS_525_HD; @@ -1116,9 +1035,8 @@ namespace DiscImageChef.DiscImages case 512512: { // DEC disk uses 256 bytes/sector - if(ImageInfo.SectorSize == 256) return MediaType.RX02; + return ImageInfo.SectorSize == 256 ? MediaType.RX02 : MediaType.ECMA_59; // ECMA disks use 128 bytes/sector - return MediaType.ECMA_59; } case 1261568: return MediaType.NEC_8_DD; case 1255168: return MediaType.ECMA_69_8; @@ -1150,9 +1068,7 @@ namespace DiscImageChef.DiscImages throw new FeatureNotPresentImageException("Lead-out not present in disk image"); } - #endregion - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -1277,7 +1193,80 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features + + struct TeleDiskHeader + { + /// <summary>"TD" or "td" depending on compression</summary> + public ushort Signature; + /// <summary>Sequence, but TeleDisk seems to complaing if != 0</summary> + public byte Sequence; + /// <summary>Random, same byte for all disks in the same set</summary> + public byte DiskSet; + /// <summary>TeleDisk version, major in high nibble, minor in low nibble</summary> + public byte Version; + /// <summary>Data rate</summary> + public byte DataRate; + /// <summary>BIOS drive type</summary> + public byte DriveType; + /// <summary>Stepping used</summary> + public byte Stepping; + /// <summary>If set means image only allocates sectors marked in-use by FAT12</summary> + public byte DosAllocation; + /// <summary>Sides of disk</summary> + public byte Sides; + /// <summary>CRC of all the previous</summary> + public ushort Crc; + } + + struct TeleDiskCommentBlockHeader + { + /// <summary>CRC of comment block after crc field</summary> + public ushort Crc; + /// <summary>Length of comment</summary> + public ushort Length; + public byte Year; + public byte Month; + public byte Day; + public byte Hour; + public byte Minute; + public byte Second; + } + + struct TeleDiskTrackHeader + { + /// <summary>Sectors in the track, 0xFF if end of disk image (there is no spoon)</summary> + public byte Sectors; + /// <summary>Cylinder the head was on</summary> + public byte Cylinder; + /// <summary>Head/side used</summary> + public byte Head; + /// <summary>Lower byte of CRC of previous fields</summary> + public byte Crc; + } + + struct TeleDiskSectorHeader + { + /// <summary>Cylinder as stored on sector address mark</summary> + public byte Cylinder; + /// <summary>Head as stored on sector address mark</summary> + public byte Head; + /// <summary>Sector number as stored on sector address mark</summary> + public byte SectorNumber; + /// <summary>Sector size</summary> + public byte SectorSize; + /// <summary>Sector flags</summary> + public byte Flags; + /// <summary>Lower byte of TeleDisk CRC of sector header, data header and data block</summary> + public byte Crc; + } + + struct TeleDiskDataHeader + { + /// <summary>Size of all data (encoded) + next field (1)</summary> + public ushort DataSize; + /// <summary>Encoding used for data block</summary> + public byte DataEncoding; + } #region LZH decompression from MAME /* This region is under following license: @@ -1436,9 +1425,7 @@ namespace DiscImageChef.DiscImages i = (short)getbuf; getbuf <<= 1; getlen--; - if(i < 0) return 1; - - return 0; + return i < 0 ? 1 : 0; } int GetByte() /* get a byte */ diff --git a/DiscImageChef.DiscImages/UDIF.cs b/DiscImageChef.DiscImages/UDIF.cs index 8997b3337..96b770ef3 100644 --- a/DiscImageChef.DiscImages/UDIF.cs +++ b/DiscImageChef.DiscImages/UDIF.cs @@ -43,15 +43,14 @@ using DiscImageChef.Filters; using Ionic.Zlib; using SharpCompress.Compressors.ADC; using SharpCompress.Compressors.BZip2; -using CompressionMode = SharpCompress.Compressors.CompressionMode; using Version = Resources.Version; + #pragma warning disable 612 namespace DiscImageChef.DiscImages { public class Udif : ImagePlugin { - #region Internal constants const uint UDIF_SIGNATURE = 0x6B6F6C79; const uint CHUNK_SIGNATURE = 0x6D697368; @@ -74,88 +73,20 @@ namespace DiscImageChef.DiscImages const string RESOURCE_FORK_KEY = "resource-fork"; const string BLOCK_KEY = "blkx"; const uint BLOCK_OS_TYPE = 0x626C6B78; - #endregion - - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct UdifFooter - { - public uint signature; - public uint version; - public uint headerSize; - public uint flags; - public ulong runningDataForkOff; - public ulong dataForkOff; - public ulong dataForkLen; - public ulong rsrcForkOff; - public ulong rsrcForkLen; - public uint segmentNumber; - public uint segmentCount; - public Guid segmentId; - public uint dataForkChkType; - public uint dataForkChkLen; - public uint dataForkChk; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reserved1; - public ulong plistOff; - public ulong plistLen; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 120)] public byte[] reserved2; - public uint masterChkType; - public uint masterChkLen; - public uint masterChk; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reserved3; - public uint imageVariant; - public ulong sectorCount; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] reserved4; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BlockHeader - { - public uint signature; - public uint version; - public ulong sectorStart; - public ulong sectorCount; - public ulong dataOffset; - public uint buffers; - public uint descriptor; - public uint reserved1; - public uint reserved2; - public uint reserved3; - public uint reserved4; - public uint reserved5; - public uint reserved6; - public uint checksumType; - public uint checksumLen; - public uint checksum; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reservedChk; - public uint chunks; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BlockChunk - { - public uint type; - public uint comment; - public ulong sector; - public ulong sectors; - public ulong offset; - public ulong length; - } - #endregion - - UdifFooter footer; - Dictionary<ulong, BlockChunk> chunks; - - Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> chunkCache; const uint MAX_CACHE_SIZE = 16777216; const uint SECTOR_SIZE = 512; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / SECTOR_SIZE; - uint currentChunkCacheSize; uint buffersize; + Dictionary<ulong, byte[]> chunkCache; + Dictionary<ulong, BlockChunk> chunks; + uint currentChunkCacheSize; + + UdifFooter footer; Stream imageStream; + Dictionary<ulong, byte[]> sectorCache; + public Udif() { Name = "Apple Universal Disk Image Format"; @@ -323,7 +254,8 @@ namespace DiscImageChef.DiscImages NSObject[] blkx = ((NSArray)blkxObj).GetArray(); - foreach(NSDictionary part in blkx.Cast<NSDictionary>()) { + foreach(NSDictionary part in blkx.Cast<NSDictionary>()) + { if(!part.TryGetValue("Name", out _)) throw new Exception("Could not retrieve Name"); if(!part.TryGetValue("Data", out NSObject dataObj)) throw new Exception("Could not retrieve Data"); @@ -456,16 +388,23 @@ namespace DiscImageChef.DiscImages bChnk.sector += bHdr.sectorStart; bChnk.offset += bHdr.dataOffset; - switch(bChnk.type) { + switch(bChnk.type) + { // TODO: Handle comments case CHUNK_TYPE_COMMNT: continue; // TODO: Handle compressed chunks case CHUNK_TYPE_KENCODE: throw new ImageNotSupportedException("Chunks compressed with KenCode are not yet supported."); - case CHUNK_TYPE_RLE: throw new ImageNotSupportedException("Chunks compressed with RLE are not yet supported."); - case CHUNK_TYPE_LZH: throw new ImageNotSupportedException("Chunks compressed with LZH are not yet supported."); - case CHUNK_TYPE_LZFSE: throw new ImageNotSupportedException("Chunks compressed with lzfse are not yet supported."); + case CHUNK_TYPE_RLE: + throw new + ImageNotSupportedException("Chunks compressed with RLE are not yet supported."); + case CHUNK_TYPE_LZH: + throw new + ImageNotSupportedException("Chunks compressed with LZH are not yet supported."); + case CHUNK_TYPE_LZFSE: + throw new + ImageNotSupportedException("Chunks compressed with lzfse are not yet supported."); } if(bChnk.type > CHUNK_TYPE_NOCOPY && bChnk.type < CHUNK_TYPE_COMMNT || @@ -510,7 +449,8 @@ namespace DiscImageChef.DiscImages bool chunkFound = false; ulong chunkStartSector = 0; - foreach(KeyValuePair<ulong, BlockChunk> kvp in chunks.Where(kvp => sectorAddress >= kvp.Key)) { + foreach(KeyValuePair<ulong, BlockChunk> kvp in chunks.Where(kvp => sectorAddress >= kvp.Key)) + { currentChunk = kvp.Value; chunkFound = true; chunkStartSector = kvp.Key; @@ -536,15 +476,20 @@ namespace DiscImageChef.DiscImages MemoryStream cmpMs = new MemoryStream(cmpBuffer); Stream decStream; - switch(currentChunk.type) { - case CHUNK_TYPE_ADC: decStream = new ADCStream(cmpMs); + switch(currentChunk.type) + { + case CHUNK_TYPE_ADC: + decStream = new ADCStream(cmpMs); break; - case CHUNK_TYPE_ZLIB: decStream = new ZlibStream(cmpMs, Ionic.Zlib.CompressionMode.Decompress); + case CHUNK_TYPE_ZLIB: + decStream = new ZlibStream(cmpMs, CompressionMode.Decompress); break; - case CHUNK_TYPE_BZIP: decStream = new BZip2Stream(cmpMs, CompressionMode.Decompress); + case CHUNK_TYPE_BZIP: + decStream = new BZip2Stream(cmpMs, SharpCompress.Compressors.CompressionMode.Decompress); break; default: - throw new ImageNotSupportedException($"Unsupported chunk type 0x{currentChunk.type:X8} found"); + throw new + ImageNotSupportedException($"Unsupported chunk type 0x{currentChunk.type:X8} found"); } #if DEBUG @@ -584,7 +529,8 @@ namespace DiscImageChef.DiscImages return sector; } - switch(currentChunk.type) { + switch(currentChunk.type) + { case CHUNK_TYPE_NOCOPY: case CHUNK_TYPE_ZERO: sector = new byte[SECTOR_SIZE]; @@ -697,7 +643,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -858,6 +803,70 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct UdifFooter + { + public uint signature; + public uint version; + public uint headerSize; + public uint flags; + public ulong runningDataForkOff; + public ulong dataForkOff; + public ulong dataForkLen; + public ulong rsrcForkOff; + public ulong rsrcForkLen; + public uint segmentNumber; + public uint segmentCount; + public Guid segmentId; + public uint dataForkChkType; + public uint dataForkChkLen; + public uint dataForkChk; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reserved1; + public ulong plistOff; + public ulong plistLen; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 120)] public byte[] reserved2; + public uint masterChkType; + public uint masterChkLen; + public uint masterChk; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reserved3; + public uint imageVariant; + public ulong sectorCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] reserved4; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BlockHeader + { + public uint signature; + public uint version; + public ulong sectorStart; + public ulong sectorCount; + public ulong dataOffset; + public uint buffers; + public uint descriptor; + public uint reserved1; + public uint reserved2; + public uint reserved3; + public uint reserved4; + public uint reserved5; + public uint reserved6; + public uint checksumType; + public uint checksumLen; + public uint checksum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 124)] public byte[] reservedChk; + public uint chunks; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BlockChunk + { + public uint type; + public uint comment; + public ulong sector; + public ulong sectors; + public ulong offset; + public ulong length; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/UkvFdi.cs b/DiscImageChef.DiscImages/UkvFdi.cs index e3089dc8d..6fca1377b 100644 --- a/DiscImageChef.DiscImages/UkvFdi.cs +++ b/DiscImageChef.DiscImages/UkvFdi.cs @@ -43,43 +43,7 @@ namespace DiscImageChef.DiscImages { public class UkvFdi : ImagePlugin { - #region Internal enumerations - [Flags] - enum DiskFlags : byte - { - WriteProtected = 1 - } - - [Flags] - enum SectorFlags : byte - { - CrcOk128 = 0x01, - CrcOk256 = 0x02, - CrcOk512 = 0x04, - CrcOk1024 = 0x08, - CrcOk2048 = 0x10, - CrcOk4096 = 0x20, - Deleted = 0x80 - } - #endregion - - #region Internal constants readonly byte[] signature = {0x46, 0x44, 0x49}; - #endregion - - #region Internal structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct FdiHeader - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] magic; - public DiskFlags flags; - public ushort cylinders; - public ushort heads; - public ushort descOff; - public ushort dataOff; - public ushort addInfoLen; - } - #endregion // Cylinder by head, sector data matrix byte[][][][] sectorsData; @@ -379,7 +343,6 @@ namespace DiscImageChef.DiscImages return (cylinder, head, sector); } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -540,6 +503,35 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [Flags] + enum DiskFlags : byte + { + WriteProtected = 1 + } + + [Flags] + enum SectorFlags : byte + { + CrcOk128 = 0x01, + CrcOk256 = 0x02, + CrcOk512 = 0x04, + CrcOk1024 = 0x08, + CrcOk2048 = 0x10, + CrcOk4096 = 0x20, + Deleted = 0x80 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct FdiHeader + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] magic; + public DiskFlags flags; + public ushort cylinders; + public ushort heads; + public ushort descOff; + public ushort dataOff; + public ushort addInfoLen; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/VDI.cs b/DiscImageChef.DiscImages/VDI.cs index 2bbed85b3..14cbec942 100644 --- a/DiscImageChef.DiscImages/VDI.cs +++ b/DiscImageChef.DiscImages/VDI.cs @@ -42,7 +42,6 @@ namespace DiscImageChef.DiscImages { public class Vdi : ImagePlugin { - #region Internal constants const uint VDI_MAGIC = 0xBEDA107F; const uint VDI_EMPTY = 0xFFFFFFFF; @@ -52,57 +51,15 @@ namespace DiscImageChef.DiscImages const string SUN_VDI = "<<< Sun VirtualBox Disk Image >>>\n"; const string INNOTEK_VDI = "<<< innotek VirtualBox Disk Image >>>\n"; const string INNOTEK_OLD_VDI = "<<< InnoTek VirtualBox Disk Image >>>\n"; - #endregion - #region Internal Structures - /// <summary> - /// VDI disk image header, little-endian - /// </summary> - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VdiHeader - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string creator; - /// <summary> - /// Magic, <see cref="Vdi.VDI_MAGIC"/> - /// </summary> - public uint magic; - /// <summary> - /// Version - /// </summary> - public ushort majorVersion; - public ushort minorVersion; - public uint headerSize; - public uint imageType; - public uint imageFlags; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string description; - public uint offsetBlocks; - public uint offsetData; - public uint cylinders; - public uint heads; - public uint spt; - public uint sectorSize; - public uint unused; - public ulong size; - public uint blockSize; - public uint blockExtraData; - public uint blocks; - public uint allocatedBlocks; - public Guid uuid; - public Guid snapshotUuid; - public Guid linkUuid; - public Guid parentUuid; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)] public byte[] garbage; - } - #endregion - - VdiHeader vHdr; + const uint MAX_CACHE_SIZE = 16777216; + const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; uint[] ibm; Stream imageStream; Dictionary<ulong, byte[]> sectorCache; - const uint MAX_CACHE_SIZE = 16777216; - const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / 512; + VdiHeader vHdr; public Vdi() { @@ -361,7 +318,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -522,6 +478,44 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + /// <summary> + /// VDI disk image header, little-endian + /// </summary> + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VdiHeader + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string creator; + /// <summary> + /// Magic, <see cref="Vdi.VDI_MAGIC" /> + /// </summary> + public uint magic; + /// <summary> + /// Version + /// </summary> + public ushort majorVersion; + public ushort minorVersion; + public uint headerSize; + public uint imageType; + public uint imageFlags; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string description; + public uint offsetBlocks; + public uint offsetData; + public uint cylinders; + public uint heads; + public uint spt; + public uint sectorSize; + public uint unused; + public ulong size; + public uint blockSize; + public uint blockExtraData; + public uint blocks; + public uint allocatedBlocks; + public Guid uuid; + public Guid snapshotUuid; + public Guid linkUuid; + public Guid parentUuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)] public byte[] garbage; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/VHD.cs b/DiscImageChef.DiscImages/VHD.cs index 89980ee39..8829288e2 100644 --- a/DiscImageChef.DiscImages/VHD.cs +++ b/DiscImageChef.DiscImages/VHD.cs @@ -45,319 +45,154 @@ namespace DiscImageChef.DiscImages { /// <inheritdoc /> /// <summary> - /// Supports Connectix/Microsoft Virtual PC hard disk image format - /// Until Virtual PC 5 there existed no format, and the hard disk image was - /// merely a sector by sector (RAW) image with a resource fork giving - /// information to Virtual PC itself. + /// Supports Connectix/Microsoft Virtual PC hard disk image format + /// Until Virtual PC 5 there existed no format, and the hard disk image was + /// merely a sector by sector (RAW) image with a resource fork giving + /// information to Virtual PC itself. /// </summary> public class Vhd : ImagePlugin { - #region Internal Structures - struct HardDiskFooter - { - /// <summary> - /// Offset 0x00, File magic number, <see cref="Vhd.IMAGE_COOKIE"/> - /// </summary> - public ulong Cookie; - /// <summary> - /// Offset 0x08, Specific feature support - /// </summary> - public uint Features; - /// <summary> - /// Offset 0x0C, File format version - /// </summary> - public uint Version; - /// <summary> - /// Offset 0x10, Offset from beginning of file to next structure - /// </summary> - public ulong Offset; - /// <summary> - /// Offset 0x18, Creation date seconds since 2000/01/01 00:00:00 UTC - /// </summary> - public uint Timestamp; - /// <summary> - /// Offset 0x1C, Application that created this disk image - /// </summary> - public uint CreatorApplication; - /// <summary> - /// Offset 0x20, Version of the application that created this disk image - /// </summary> - public uint CreatorVersion; - /// <summary> - /// Offset 0x24, Host operating system of the application that created this disk image - /// </summary> - public uint CreatorHostOs; - /// <summary> - /// Offset 0x28, Original hard disk size, in bytes - /// </summary> - public ulong OriginalSize; - /// <summary> - /// Offset 0x30, Current hard disk size, in bytes - /// </summary> - public ulong CurrentSize; - /// <summary> - /// Offset 0x38, CHS geometry - /// Cylinder mask = 0xFFFF0000 - /// Heads mask = 0x0000FF00 - /// Sectors mask = 0x000000FF - /// </summary> - public uint DiskGeometry; - /// <summary> - /// Offset 0x3C, Disk image type - /// </summary> - public uint DiskType; - /// <summary> - /// Offset 0x40, Checksum for this structure - /// </summary> - public uint Checksum; - /// <summary> - /// Offset 0x44, UUID, used to associate parent with differencing disk images - /// </summary> - public Guid UniqueId; - /// <summary> - /// Offset 0x54, If set, system is saved, so compaction and expansion cannot be performed - /// </summary> - public byte SavedState; - /// <summary> - /// Offset 0x55, 427 bytes reserved, should contain zeros. - /// </summary> - public byte[] Reserved; - } - - struct ParentLocatorEntry - { - /// <summary> - /// Offset 0x00, Describes the platform specific type this entry belongs to - /// </summary> - public uint PlatformCode; - /// <summary> - /// Offset 0x04, Describes the number of 512 bytes sectors used by this entry - /// </summary> - public uint PlatformDataSpace; - /// <summary> - /// Offset 0x08, Describes this entry's size in bytes - /// </summary> - public uint PlatformDataLength; - /// <summary> - /// Offset 0x0c, Reserved - /// </summary> - public uint Reserved; - /// <summary> - /// Offset 0x10, Offset on disk image this entry resides on - /// </summary> - public ulong PlatformDataOffset; - } - - struct DynamicDiskHeader - { - /// <summary> - /// Offset 0x00, Header magic, <see cref="Vhd.DYNAMIC_COOKIE"/> - /// </summary> - public ulong Cookie; - /// <summary> - /// Offset 0x08, Offset to next structure on disk image. - /// Currently unused, 0xFFFFFFFF - /// </summary> - public ulong DataOffset; - /// <summary> - /// Offset 0x10, Offset of the Block Allocation Table (BAT) - /// </summary> - public ulong TableOffset; - /// <summary> - /// Offset 0x18, Version of this header - /// </summary> - public uint HeaderVersion; - /// <summary> - /// Offset 0x1C, Maximum entries present in the BAT - /// </summary> - public uint MaxTableEntries; - /// <summary> - /// Offset 0x20, Size of a block in bytes - /// Should always be a power of two of 512 - /// </summary> - public uint BlockSize; - /// <summary> - /// Offset 0x24, Checksum of this header - /// </summary> - public uint Checksum; - /// <summary> - /// Offset 0x28, UUID of parent disk image for differencing type - /// </summary> - public Guid ParentId; - /// <summary> - /// Offset 0x38, Timestamp of parent disk image - /// </summary> - public uint ParentTimestamp; - /// <summary> - /// Offset 0x3C, Reserved - /// </summary> - public uint Reserved; - /// <summary> - /// Offset 0x40, 512 bytes UTF-16 of parent disk image filename - /// </summary> - public string ParentName; - /// <summary> - /// Offset 0x240, Parent disk image locator entry, <see cref="ParentLocatorEntry"/> - /// </summary> - public ParentLocatorEntry[] LocatorEntries; - /// <summary> - /// Offset 0x300, 256 reserved bytes - /// </summary> - public byte[] Reserved2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct BatSector - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public uint[] blockPointer; - } - #endregion - - #region Internal Constants /// <summary> - /// File magic number, "conectix" + /// File magic number, "conectix" /// </summary> const ulong IMAGE_COOKIE = 0x636F6E6563746978; /// <summary> - /// Dynamic disk header magic, "cxsparse" + /// Dynamic disk header magic, "cxsparse" /// </summary> const ulong DYNAMIC_COOKIE = 0x6378737061727365; /// <summary> - /// Disk image is candidate for deletion on shutdown + /// Disk image is candidate for deletion on shutdown /// </summary> const uint FEATURES_TEMPORARY = 0x00000001; /// <summary> - /// Unknown, set from Virtual PC for Mac 7 onwards + /// Unknown, set from Virtual PC for Mac 7 onwards /// </summary> const uint FEATURES_RESERVED = 0x00000002; /// <summary> - /// Unknown + /// Unknown /// </summary> const uint FEATURES_UNKNOWN = 0x00000100; /// <summary> - /// Only known version + /// Only known version /// </summary> const uint VERSION1 = 0x00010000; /// <summary> - /// Created by Virtual PC, "vpc " + /// Created by Virtual PC, "vpc " /// </summary> const uint CREATOR_VIRTUAL_PC = 0x76706320; /// <summary> - /// Created by Virtual Server, "vs " + /// Created by Virtual Server, "vs " /// </summary> const uint CREATOR_VIRTUAL_SERVER = 0x76732020; /// <summary> - /// Created by QEMU, "qemu" + /// Created by QEMU, "qemu" /// </summary> const uint CREATOR_QEMU = 0x71656D75; /// <summary> - /// Created by VirtualBox, "vbox" + /// Created by VirtualBox, "vbox" /// </summary> const uint CREATOR_VIRTUAL_BOX = 0x76626F78; /// <summary> - /// Disk image created by Virtual Server 2004 + /// Disk image created by Virtual Server 2004 /// </summary> const uint VERSION_VIRTUAL_SERVER2004 = 0x00010000; /// <summary> - /// Disk image created by Virtual PC 2004 + /// Disk image created by Virtual PC 2004 /// </summary> const uint VERSION_VIRTUAL_PC2004 = 0x00050000; /// <summary> - /// Disk image created by Virtual PC 2007 + /// Disk image created by Virtual PC 2007 /// </summary> const uint VERSION_VIRTUAL_PC2007 = 0x00050003; /// <summary> - /// Disk image created by Virtual PC for Mac 5, 6 or 7 + /// Disk image created by Virtual PC for Mac 5, 6 or 7 /// </summary> const uint VERSION_VIRTUAL_PC_MAC = 0x00040000; /// <summary> - /// Disk image created in Windows, "Wi2k" + /// Disk image created in Windows, "Wi2k" /// </summary> const uint CREATOR_WINDOWS = 0x5769326B; /// <summary> - /// Disk image created in Macintosh, "Mac " + /// Disk image created in Macintosh, "Mac " /// </summary> const uint CREATOR_MACINTOSH = 0x4D616320; /// <summary> - /// Seen in Virtual PC for Mac for dynamic and fixed images + /// Seen in Virtual PC for Mac for dynamic and fixed images /// </summary> const uint CREATOR_MACINTOSH_OLD = 0x00000000; /// <summary> - /// Disk image type is none, useless? + /// Disk image type is none, useless? /// </summary> const uint TYPE_NONE = 0; /// <summary> - /// Deprecated disk image type + /// Deprecated disk image type /// </summary> const uint TYPE_DEPRECATED1 = 1; /// <summary> - /// Fixed disk image type + /// Fixed disk image type /// </summary> const uint TYPE_FIXED = 2; /// <summary> - /// Dynamic disk image type + /// Dynamic disk image type /// </summary> const uint TYPE_DYNAMIC = 3; /// <summary> - /// Differencing disk image type + /// Differencing disk image type /// </summary> const uint TYPE_DIFFERENCING = 4; /// <summary> - /// Deprecated disk image type + /// Deprecated disk image type /// </summary> const uint TYPE_DEPRECATED2 = 5; /// <summary> - /// Deprecated disk image type + /// Deprecated disk image type /// </summary> const uint TYPE_DEPRECATED3 = 6; /// <summary> - /// Means platform locator is unused + /// Means platform locator is unused /// </summary> const uint PLATFORM_CODE_UNUSED = 0x00000000; /// <summary> - /// Stores a relative path string for Windows, unknown locale used, deprecated, "Wi2r" + /// Stores a relative path string for Windows, unknown locale used, deprecated, "Wi2r" /// </summary> const uint PLATFORM_CODE_WINDOWS_RELATIVE = 0x57693272; /// <summary> - /// Stores an absolute path string for Windows, unknown locale used, deprecated, "Wi2k" + /// Stores an absolute path string for Windows, unknown locale used, deprecated, "Wi2k" /// </summary> const uint PLATFORM_CODE_WINDOWS_ABSOLUTE = 0x5769326B; /// <summary> - /// Stores a relative path string for Windows in UTF-16, "W2ru" + /// Stores a relative path string for Windows in UTF-16, "W2ru" /// </summary> const uint PLATFORM_CODE_WINDOWS_RELATIVE_U = 0x57327275; /// <summary> - /// Stores an absolute path string for Windows in UTF-16, "W2ku" + /// Stores an absolute path string for Windows in UTF-16, "W2ku" /// </summary> const uint PLATFORM_CODE_WINDOWS_ABSOLUTE_U = 0x57326B75; /// <summary> - /// Stores a Mac OS alias as a blob, "Mac " + /// Stores a Mac OS alias as a blob, "Mac " /// </summary> const uint PLATFORM_CODE_MACINTOSH_ALIAS = 0x4D616320; /// <summary> - /// Stores a Mac OS X URI (RFC-2396) absolute path in UTF-8, "MacX" + /// Stores a Mac OS X URI (RFC-2396) absolute path in UTF-8, "MacX" /// </summary> const uint PLATFORM_CODE_MACINTOSH_URI = 0x4D616358; - #endregion - - #region Internal variables - HardDiskFooter thisFooter; - DynamicDiskHeader thisDynamic; - DateTime thisDateTime; - DateTime parentDateTime; - Filter thisFilter; - uint[] blockAllocationTable; uint bitmapSize; + uint[] blockAllocationTable; byte[][] locatorEntriesData; + DateTime parentDateTime; ImagePlugin parentImage; - #endregion + DateTime thisDateTime; + DynamicDiskHeader thisDynamic; + Filter thisFilter; + + HardDiskFooter thisFooter; public Vhd() { @@ -388,7 +223,6 @@ namespace DiscImageChef.DiscImages }; } - #region public methods public override bool IdentifyImage(Filter imageFilter) { Stream imageStream = imageFilter.GetDataForkStream(); @@ -787,7 +621,8 @@ namespace DiscImageChef.DiscImages // This does the big-endian trick but reverses the order of elements also Array.Reverse(batSectorBytes); GCHandle handle = GCHandle.Alloc(batSectorBytes, GCHandleType.Pinned); - BatSector batSector = (BatSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BatSector)); + BatSector batSector = + (BatSector)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BatSector)); handle.Free(); // This restores the order of elements Array.Reverse(batSector.blockPointer); @@ -1037,7 +872,7 @@ namespace DiscImageChef.DiscImages case TYPE_DIFFERENCING: { // Block number for BAT searching - uint blockNumber = (uint)Math.Floor((sectorAddress / (thisDynamic.BlockSize / 512.0))); + uint blockNumber = (uint)Math.Floor(sectorAddress / (thisDynamic.BlockSize / 512.0)); // Sector number inside of block uint sectorInBlock = (uint)(sectorAddress % (thisDynamic.BlockSize / 512)); @@ -1116,7 +951,7 @@ namespace DiscImageChef.DiscImages case TYPE_DYNAMIC: { // Block number for BAT searching - uint blockNumber = (uint)Math.Floor((sectorAddress / (thisDynamic.BlockSize / 512.0))); + uint blockNumber = (uint)Math.Floor(sectorAddress / (thisDynamic.BlockSize / 512.0)); // Sector number inside of block uint sectorInBlock = (uint)(sectorAddress % (thisDynamic.BlockSize / 512)); // How many sectors before reaching end of block @@ -1186,18 +1021,14 @@ namespace DiscImageChef.DiscImages } } } - #endregion - #region private methods static uint VhdChecksum(IEnumerable<byte> data) { uint checksum = data.Aggregate<byte, uint>(0, (current, b) => current + b); return ~checksum; } - #endregion - #region Unsupported features public override string GetImageComments() { return null; @@ -1363,6 +1194,164 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + struct HardDiskFooter + { + /// <summary> + /// Offset 0x00, File magic number, <see cref="Vhd.IMAGE_COOKIE" /> + /// </summary> + public ulong Cookie; + /// <summary> + /// Offset 0x08, Specific feature support + /// </summary> + public uint Features; + /// <summary> + /// Offset 0x0C, File format version + /// </summary> + public uint Version; + /// <summary> + /// Offset 0x10, Offset from beginning of file to next structure + /// </summary> + public ulong Offset; + /// <summary> + /// Offset 0x18, Creation date seconds since 2000/01/01 00:00:00 UTC + /// </summary> + public uint Timestamp; + /// <summary> + /// Offset 0x1C, Application that created this disk image + /// </summary> + public uint CreatorApplication; + /// <summary> + /// Offset 0x20, Version of the application that created this disk image + /// </summary> + public uint CreatorVersion; + /// <summary> + /// Offset 0x24, Host operating system of the application that created this disk image + /// </summary> + public uint CreatorHostOs; + /// <summary> + /// Offset 0x28, Original hard disk size, in bytes + /// </summary> + public ulong OriginalSize; + /// <summary> + /// Offset 0x30, Current hard disk size, in bytes + /// </summary> + public ulong CurrentSize; + /// <summary> + /// Offset 0x38, CHS geometry + /// Cylinder mask = 0xFFFF0000 + /// Heads mask = 0x0000FF00 + /// Sectors mask = 0x000000FF + /// </summary> + public uint DiskGeometry; + /// <summary> + /// Offset 0x3C, Disk image type + /// </summary> + public uint DiskType; + /// <summary> + /// Offset 0x40, Checksum for this structure + /// </summary> + public uint Checksum; + /// <summary> + /// Offset 0x44, UUID, used to associate parent with differencing disk images + /// </summary> + public Guid UniqueId; + /// <summary> + /// Offset 0x54, If set, system is saved, so compaction and expansion cannot be performed + /// </summary> + public byte SavedState; + /// <summary> + /// Offset 0x55, 427 bytes reserved, should contain zeros. + /// </summary> + public byte[] Reserved; + } + + struct ParentLocatorEntry + { + /// <summary> + /// Offset 0x00, Describes the platform specific type this entry belongs to + /// </summary> + public uint PlatformCode; + /// <summary> + /// Offset 0x04, Describes the number of 512 bytes sectors used by this entry + /// </summary> + public uint PlatformDataSpace; + /// <summary> + /// Offset 0x08, Describes this entry's size in bytes + /// </summary> + public uint PlatformDataLength; + /// <summary> + /// Offset 0x0c, Reserved + /// </summary> + public uint Reserved; + /// <summary> + /// Offset 0x10, Offset on disk image this entry resides on + /// </summary> + public ulong PlatformDataOffset; + } + + struct DynamicDiskHeader + { + /// <summary> + /// Offset 0x00, Header magic, <see cref="Vhd.DYNAMIC_COOKIE" /> + /// </summary> + public ulong Cookie; + /// <summary> + /// Offset 0x08, Offset to next structure on disk image. + /// Currently unused, 0xFFFFFFFF + /// </summary> + public ulong DataOffset; + /// <summary> + /// Offset 0x10, Offset of the Block Allocation Table (BAT) + /// </summary> + public ulong TableOffset; + /// <summary> + /// Offset 0x18, Version of this header + /// </summary> + public uint HeaderVersion; + /// <summary> + /// Offset 0x1C, Maximum entries present in the BAT + /// </summary> + public uint MaxTableEntries; + /// <summary> + /// Offset 0x20, Size of a block in bytes + /// Should always be a power of two of 512 + /// </summary> + public uint BlockSize; + /// <summary> + /// Offset 0x24, Checksum of this header + /// </summary> + public uint Checksum; + /// <summary> + /// Offset 0x28, UUID of parent disk image for differencing type + /// </summary> + public Guid ParentId; + /// <summary> + /// Offset 0x38, Timestamp of parent disk image + /// </summary> + public uint ParentTimestamp; + /// <summary> + /// Offset 0x3C, Reserved + /// </summary> + public uint Reserved; + /// <summary> + /// Offset 0x40, 512 bytes UTF-16 of parent disk image filename + /// </summary> + public string ParentName; + /// <summary> + /// Offset 0x240, Parent disk image locator entry, <see cref="ParentLocatorEntry" /> + /// </summary> + public ParentLocatorEntry[] LocatorEntries; + /// <summary> + /// Offset 0x300, 256 reserved bytes + /// </summary> + public byte[] Reserved2; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BatSector + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public uint[] blockPointer; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/VHDX.cs b/DiscImageChef.DiscImages/VHDX.cs index 7afcf9d96..dfe64487a 100644 --- a/DiscImageChef.DiscImages/VHDX.cs +++ b/DiscImageChef.DiscImages/VHDX.cs @@ -44,220 +44,10 @@ namespace DiscImageChef.DiscImages { public class Vhdx : ImagePlugin { - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxIdentifier - { - /// <summary> - /// Signature, <see cref="Vhdx.VHDX_SIGNATURE"/> - /// </summary> - public ulong signature; - /// <summary> - /// UTF-16 string containing creator - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] public byte[] creator; - } - -#pragma warning disable 649 -#pragma warning disable 169 - struct VhdxHeader - { - /// <summary> - /// Signature, <see cref="Vhdx.VHDX_HEADER_SIG"/> - /// </summary> - public uint Signature; - /// <summary> - /// CRC-32C of whole 4096 bytes header with this field set to 0 - /// </summary> - public uint Checksum; - /// <summary> - /// Sequence number - /// </summary> - public ulong Sequence; - /// <summary> - /// Unique identifier for file contents, must be changed on first write to metadata - /// </summary> - public Guid FileWriteGuid; - /// <summary> - /// Unique identifier for disk contents, must be changed on first write to metadata or data - /// </summary> - public Guid DataWriteGuid; - /// <summary> - /// Unique identifier for log entries - /// </summary> - public Guid LogGuid; - /// <summary> - /// Version of log format - /// </summary> - public ushort LogVersion; - /// <summary> - /// Version of VHDX format - /// </summary> - public ushort Version; - /// <summary> - /// Length in bytes of the log - /// </summary> - public uint LogLength; - /// <summary> - /// Offset from image start to the log - /// </summary> - public ulong LogOffset; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4016)] public byte[] Reserved; - } -#pragma warning restore 649 -#pragma warning restore 169 - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxRegionTableHeader - { - /// <summary> - /// Signature, <see cref="Vhdx.VHDX_REGION_SIG"/> - /// </summary> - public uint signature; - /// <summary> - /// CRC-32C of whole 64Kb table with this field set to 0 - /// </summary> - public uint checksum; - /// <summary> - /// How many entries follow this table - /// </summary> - public uint entries; - /// <summary> - /// Reserved - /// </summary> - public uint reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxRegionTableEntry - { - /// <summary> - /// Object identifier - /// </summary> - public Guid guid; - /// <summary> - /// Offset in image of the object - /// </summary> - public ulong offset; - /// <summary> - /// Length in bytes of the object - /// </summary> - public uint length; - /// <summary> - /// Flags - /// </summary> - public uint flags; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxMetadataTableHeader - { - /// <summary> - /// Signature - /// </summary> - public ulong signature; - /// <summary> - /// Reserved - /// </summary> - public ushort reserved; - /// <summary> - /// How many entries are in the table - /// </summary> - public ushort entries; - /// <summary> - /// Reserved - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public uint[] reserved2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxMetadataTableEntry - { - /// <summary> - /// Metadata ID - /// </summary> - public Guid itemId; - /// <summary> - /// Offset relative to start of metadata region - /// </summary> - public uint offset; - /// <summary> - /// Length in bytes - /// </summary> - public uint length; - /// <summary> - /// Flags - /// </summary> - public uint flags; - /// <summary> - /// Reserved - /// </summary> - public uint reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxFileParameters - { - /// <summary> - /// Block size in bytes - /// </summary> - public uint blockSize; - /// <summary> - /// Flags - /// </summary> - public uint flags; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxParentLocatorHeader - { - /// <summary> - /// Type of parent virtual disk - /// </summary> - public Guid locatorType; - public ushort reserved; - /// <summary> - /// How many KVPs are in this parent locator - /// </summary> - public ushort keyValueCount; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VhdxParentLocatorEntry - { - /// <summary> - /// Offset from metadata to key - /// </summary> - public uint keyOffset; - /// <summary> - /// Offset from metadata to value - /// </summary> - public uint valueOffset; - /// <summary> - /// Size of key - /// </summary> - public ushort keyLength; - /// <summary> - /// Size of value - /// </summary> - public ushort valueLength; - } - #endregion - - #region Internal Constants const ulong VHDX_SIGNATURE = 0x656C696678646876; const uint VHDX_HEADER_SIG = 0x64616568; const uint VHDX_REGION_SIG = 0x69676572; const ulong VHDX_METADATA_SIG = 0x617461646174656D; - readonly Guid batGuid = new Guid("2DC27766-F623-4200-9D64-115E9BFD4A08"); - readonly Guid metadataGuid = new Guid("8B7CA206-4790-4B9A-B8FE-575F050F886E"); - readonly Guid fileParametersGuid = new Guid("CAA16737-FA36-4D43-B3B6-33F0AA44E76B"); - readonly Guid virtualDiskSizeGuid = new Guid("2FA54224-CD1B-4876-B211-5DBED83BF4B8"); - readonly Guid page83DataGuid = new Guid("BECA12AB-B2E6-4523-93EF-C309E000C746"); - readonly Guid logicalSectorSizeGuid = new Guid("8141BF1D-A96F-4709-BA47-F233A8FAAB5F"); - readonly Guid physicalSectorSizeGuid = new Guid("CDA348C7-445D-4471-9CC9-E9885251C556"); - readonly Guid parentLocatorGuid = new Guid("A8D35F2D-B30B-454D-ABF7-D3D84834AB0C"); - readonly Guid parentTypeVhdxGuid = new Guid("B04AEFB7-D19E-4A81-B789-25B8E9445913"); const string PARENT_LINKAGE_KEY = "parent_linkage"; const string PARENT_LINKAGE2_KEY = "parent_linkage2"; @@ -293,44 +83,50 @@ namespace DiscImageChef.DiscImages const ulong BAT_FILE_OFFSET_MASK = 0xFFFFFFFFFFFC0000; const ulong BAT_FLAGS_MASK = 0x7; const ulong BAT_RESERVED_MASK = 0x3FFF8; - #endregion - #region Internal variables - ulong virtualDiskSize; - Guid page83Data; - uint logicalSectorSize; - uint physicalSectorSize; - - VhdxIdentifier vhdxId; - VhdxHeader vHdr; - VhdxRegionTableHeader vRegHdr; - VhdxRegionTableEntry[] vRegs; - VhdxMetadataTableHeader vMetHdr; - VhdxMetadataTableEntry[] vMets; - VhdxFileParameters vFileParms; - VhdxParentLocatorHeader vParHdr; - VhdxParentLocatorEntry[] vPars; + const int MAX_CACHE_SIZE = 16777216; + readonly Guid batGuid = new Guid("2DC27766-F623-4200-9D64-115E9BFD4A08"); + readonly Guid fileParametersGuid = new Guid("CAA16737-FA36-4D43-B3B6-33F0AA44E76B"); + readonly Guid logicalSectorSizeGuid = new Guid("8141BF1D-A96F-4709-BA47-F233A8FAAB5F"); + readonly Guid metadataGuid = new Guid("8B7CA206-4790-4B9A-B8FE-575F050F886E"); + readonly Guid page83DataGuid = new Guid("BECA12AB-B2E6-4523-93EF-C309E000C746"); + readonly Guid parentLocatorGuid = new Guid("A8D35F2D-B30B-454D-ABF7-D3D84834AB0C"); + readonly Guid parentTypeVhdxGuid = new Guid("B04AEFB7-D19E-4A81-B789-25B8E9445913"); + readonly Guid physicalSectorSizeGuid = new Guid("CDA348C7-445D-4471-9CC9-E9885251C556"); + readonly Guid virtualDiskSizeGuid = new Guid("2FA54224-CD1B-4876-B211-5DBED83BF4B8"); long batOffset; - long metadataOffset; + + ulong[] blockAllocationTable; + Dictionary<ulong, byte[]> blockCache; long chunkRatio; ulong dataBlocks; - - ulong[] blockAllocationTable; - ulong[] sectorBitmapPointers; - byte[] sectorBitmap; - ImagePlugin parentImage; bool hasParent; Stream imageStream; - - const int MAX_CACHE_SIZE = 16777216; + uint logicalSectorSize; int maxBlockCache; int maxSectorCache; + long metadataOffset; + Guid page83Data; + ImagePlugin parentImage; + uint physicalSectorSize; + byte[] sectorBitmap; + ulong[] sectorBitmapPointers; Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> blockCache; - #endregion + VhdxFileParameters vFileParms; + VhdxHeader vHdr; + + VhdxIdentifier vhdxId; + + ulong virtualDiskSize; + VhdxMetadataTableHeader vMetHdr; + VhdxMetadataTableEntry[] vMets; + VhdxParentLocatorHeader vParHdr; + VhdxParentLocatorEntry[] vPars; + VhdxRegionTableHeader vRegHdr; + VhdxRegionTableEntry[] vRegs; public Vhdx() { @@ -361,7 +157,6 @@ namespace DiscImageChef.DiscImages }; } - #region public methods public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -625,8 +420,10 @@ namespace DiscImageChef.DiscImages parentWorks = true; break; } - catch { // ignored - } + catch + { + // ignored + } } else if(string.Compare(entryType, VOLUME_PATH_KEY, StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(entryType, ABSOLUTE_WIN32_PATH_KEY, StringComparison.OrdinalIgnoreCase) == 0) @@ -645,8 +442,10 @@ namespace DiscImageChef.DiscImages parentWorks = true; break; } - catch { // ignored - } + catch + { + // ignored + } } } @@ -700,8 +499,10 @@ namespace DiscImageChef.DiscImages MemoryStream sectorBmpMs = new MemoryStream(); foreach(ulong pt in sectorBitmapPointers) - switch(pt & BAT_FLAGS_MASK) { - case SECTOR_BITMAP_NOT_PRESENT: sectorBmpMs.Write(new byte[1048576], 0, 1048576); + switch(pt & BAT_FLAGS_MASK) + { + case SECTOR_BITMAP_NOT_PRESENT: + sectorBmpMs.Write(new byte[1048576], 0, 1048576); break; case SECTOR_BITMAP_PRESENT: stream.Seek((long)((pt & BAT_FILE_OFFSET_MASK) * 1048576), SeekOrigin.Begin); @@ -839,10 +640,13 @@ namespace DiscImageChef.DiscImages ulong blkFlags = blkPtr & BAT_FLAGS_MASK; if((blkPtr & BAT_RESERVED_MASK) != 0) - throw new ImageNotSupportedException($"Unknown flags (0x{blkPtr & BAT_RESERVED_MASK:X16}) set in block pointer"); + throw new + ImageNotSupportedException($"Unknown flags (0x{blkPtr & BAT_RESERVED_MASK:X16}) set in block pointer"); - switch(blkFlags & BAT_FLAGS_MASK) { - case PAYLOAD_BLOCK_NOT_PRESENT: return hasParent ? parentImage.ReadSector(sectorAddress) : new byte[logicalSectorSize]; + switch(blkFlags & BAT_FLAGS_MASK) + { + case PAYLOAD_BLOCK_NOT_PRESENT: + return hasParent ? parentImage.ReadSector(sectorAddress) : new byte[logicalSectorSize]; case PAYLOAD_BLOCK_UNDEFINED: case PAYLOAD_BLOCK_ZERO: case PAYLOAD_BLOCK_UNMAPPER: return new byte[logicalSectorSize]; @@ -894,18 +698,14 @@ namespace DiscImageChef.DiscImages return ms.ToArray(); } - #endregion - #region private methods - static uint VhdxChecksum(byte[] data) + static uint VhdxChecksum(IEnumerable<byte> data) { uint checksum = data.Aggregate<byte, uint>(0, (current, b) => current + b); return ~checksum; } - #endregion - #region Unsupported features public override string GetImageComments() { return null; @@ -1071,6 +871,203 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxIdentifier + { + /// <summary> + /// Signature, <see cref="Vhdx.VHDX_SIGNATURE" /> + /// </summary> + public ulong signature; + /// <summary> + /// UTF-16 string containing creator + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] public byte[] creator; + } + +#pragma warning disable 649 +#pragma warning disable 169 + struct VhdxHeader + { + /// <summary> + /// Signature, <see cref="Vhdx.VHDX_HEADER_SIG" /> + /// </summary> + public uint Signature; + /// <summary> + /// CRC-32C of whole 4096 bytes header with this field set to 0 + /// </summary> + public uint Checksum; + /// <summary> + /// Sequence number + /// </summary> + public ulong Sequence; + /// <summary> + /// Unique identifier for file contents, must be changed on first write to metadata + /// </summary> + public Guid FileWriteGuid; + /// <summary> + /// Unique identifier for disk contents, must be changed on first write to metadata or data + /// </summary> + public Guid DataWriteGuid; + /// <summary> + /// Unique identifier for log entries + /// </summary> + public Guid LogGuid; + /// <summary> + /// Version of log format + /// </summary> + public ushort LogVersion; + /// <summary> + /// Version of VHDX format + /// </summary> + public ushort Version; + /// <summary> + /// Length in bytes of the log + /// </summary> + public uint LogLength; + /// <summary> + /// Offset from image start to the log + /// </summary> + public ulong LogOffset; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4016)] public byte[] Reserved; + } +#pragma warning restore 649 +#pragma warning restore 169 + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxRegionTableHeader + { + /// <summary> + /// Signature, <see cref="Vhdx.VHDX_REGION_SIG" /> + /// </summary> + public uint signature; + /// <summary> + /// CRC-32C of whole 64Kb table with this field set to 0 + /// </summary> + public uint checksum; + /// <summary> + /// How many entries follow this table + /// </summary> + public uint entries; + /// <summary> + /// Reserved + /// </summary> + public uint reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxRegionTableEntry + { + /// <summary> + /// Object identifier + /// </summary> + public Guid guid; + /// <summary> + /// Offset in image of the object + /// </summary> + public ulong offset; + /// <summary> + /// Length in bytes of the object + /// </summary> + public uint length; + /// <summary> + /// Flags + /// </summary> + public uint flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxMetadataTableHeader + { + /// <summary> + /// Signature + /// </summary> + public ulong signature; + /// <summary> + /// Reserved + /// </summary> + public ushort reserved; + /// <summary> + /// How many entries are in the table + /// </summary> + public ushort entries; + /// <summary> + /// Reserved + /// </summary> + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public uint[] reserved2; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxMetadataTableEntry + { + /// <summary> + /// Metadata ID + /// </summary> + public Guid itemId; + /// <summary> + /// Offset relative to start of metadata region + /// </summary> + public uint offset; + /// <summary> + /// Length in bytes + /// </summary> + public uint length; + /// <summary> + /// Flags + /// </summary> + public uint flags; + /// <summary> + /// Reserved + /// </summary> + public uint reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxFileParameters + { + /// <summary> + /// Block size in bytes + /// </summary> + public uint blockSize; + /// <summary> + /// Flags + /// </summary> + public uint flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxParentLocatorHeader + { + /// <summary> + /// Type of parent virtual disk + /// </summary> + public Guid locatorType; + public ushort reserved; + /// <summary> + /// How many KVPs are in this parent locator + /// </summary> + public ushort keyValueCount; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VhdxParentLocatorEntry + { + /// <summary> + /// Offset from metadata to key + /// </summary> + public uint keyOffset; + /// <summary> + /// Offset from metadata to value + /// </summary> + public uint valueOffset; + /// <summary> + /// Size of key + /// </summary> + public ushort keyLength; + /// <summary> + /// Size of value + /// </summary> + public ushort valueLength; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/VMware.cs b/DiscImageChef.DiscImages/VMware.cs index f0e60200a..b3b9b707b 100644 --- a/DiscImageChef.DiscImages/VMware.cs +++ b/DiscImageChef.DiscImages/VMware.cs @@ -44,7 +44,6 @@ namespace DiscImageChef.DiscImages { public class VMware : ImagePlugin { - #region Internal constants const uint VMWARE_EXTENT_MAGIC = 0x564D444B; const uint VMWARE_COW_MAGIC = 0x44574F43; @@ -68,25 +67,21 @@ namespace DiscImageChef.DiscImages const string VM_TYPE_STREAM = "streamOptimized"; const string DDF_MAGIC = "# Disk DescriptorFile"; - readonly byte[] ddfMagicBytes = - { - 0x23, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6F, 0x72, 0x46, - 0x69, 0x6C, 0x65 - }; - const string VERSION_REGEX = "^\\s*version\\s*=\\s*(?<version>\\d+)$"; - const string CID_REGEX = "^\\s*CID\\s*=\\s*(?<cid>[0123456789abcdef]{8})$"; - const string PAREN_CID_REGEX = "^\\s*parentCID\\s*=\\s*(?<cid>[0123456789abcdef]{8})$"; - const string TYPE_REGEX = + const string REGEX_VERSION = "^\\s*version\\s*=\\s*(?<version>\\d+)$"; + const string REGEX_CID = "^\\s*CID\\s*=\\s*(?<cid>[0123456789abcdef]{8})$"; + const string REGEX_CID_PARENT = "^\\s*parentCID\\s*=\\s*(?<cid>[0123456789abcdef]{8})$"; + const string REGEX_TYPE = "^\\s*createType\\s*=\\s*\\\"(?<type>custom|monolithicSparse|monolithicFlat|twoGbMaxExtentSparse|twoGbMaxExtentFlat|fullDevice|partitionedDevice|vmfs|vmfsPreallocated|vmfsEagerZeroedThick|vmfsThin|vmfsSparse|vmfsRDM|vmfsRawDeviceMap|vmfsRDMP|vmfsPassthroughRawDeviceMap|vmfsRaw|streamOptimized)\\\"$" ; - const string EXTENT_REGEX = + const string REGEX_EXTENT = "^\\s*(?<access>(RW|RDONLY|NOACCESS))\\s+(?<sectors>\\d+)\\s+(?<type>(FLAT|SPARSE|ZERO|VMFS|VMFSSPARSE|VMFSRDM|VMFSRAW))\\s+\\\"(?<filename>.+)\\\"(\\s*(?<offset>\\d+))?$" ; - const string DDB_TYPE_REGEX = "^\\s*ddb\\.adapterType\\s*=\\s*\\\"(?<type>ide|buslogic|lsilogic|legacyESX)\\\"$"; - const string DDB_SECTORS_REGEX = "^\\s*ddb\\.geometry\\.sectors\\s*=\\s*\\\"(?<sectors>\\d+)\\\"$"; - const string DDB_HEADS_REGEX = "^\\s*ddb\\.geometry\\.heads\\s*=\\s*\\\"(?<heads>\\d+)\\\"$"; - const string DDB_CYLINDERS_REGEX = "^\\s*ddb\\.geometry\\.cylinders\\s*=\\s*\\\"(?<cylinders>\\d+)\\\"$"; + const string REGEX_DDB_TYPE = + "^\\s*ddb\\.adapterType\\s*=\\s*\\\"(?<type>ide|buslogic|lsilogic|legacyESX)\\\"$"; + const string REGEX_DDB_SECTORS = "^\\s*ddb\\.geometry\\.sectors\\s*=\\s*\\\"(?<sectors>\\d+)\\\"$"; + const string REGEX_DDB_HEADS = "^\\s*ddb\\.geometry\\.heads\\s*=\\s*\\\"(?<heads>\\d+)\\\"$"; + const string REGEX_DDB_CYLINDERS = "^\\s*ddb\\.geometry\\.cylinders\\s*=\\s*\\\"(?<cylinders>\\d+)\\\"$"; const string PARENT_REGEX = "^\\s*parentFileNameHint\\s*=\\s*\\\"(?<filename>.+)\\\"$"; const uint FLAGS_VALID_NEW_LINE = 0x01; @@ -97,93 +92,36 @@ namespace DiscImageChef.DiscImages const ushort COMPRESSION_NONE = 0; const ushort COMPRESSION_DEFLATE = 1; - #endregion - - #region Internal Structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VMwareExtentHeader - { - public uint magic; - public uint version; - public uint flags; - public ulong capacity; - public ulong grainSize; - public ulong descriptorOffset; - public ulong descriptorSize; - public uint GTEsPerGT; - public ulong rgdOffset; - public ulong gdOffset; - public ulong overhead; - [MarshalAs(UnmanagedType.U1)] public bool uncleanShutdown; - public byte singleEndLineChar; - public byte nonEndLineChar; - public byte doubleEndLineChar1; - public byte doubleEndLineChar2; - public ushort compression; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 433)] public byte[] padding; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct VMwareCowHeader - { - public uint magic; - public uint version; - public uint flags; - public uint sectors; - public uint grainSize; - public uint gdOffset; - public uint numGDEntries; - public uint freeSector; - public uint cylinders; - public uint heads; - public uint spt; - // It stats on cylinders, above, but, don't care - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024 - 12)] public byte[] parentFileName; - public uint parentGeneration; - public uint generation; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] public byte[] name; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] public byte[] description; - public uint savedGeneration; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] reserved; - [MarshalAs(UnmanagedType.U1)] public bool uncleanShutdown; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 396)] public byte[] padding; - } - #endregion - - struct VMwareExtent - { - public string Access; - public uint Sectors; - public string Type; - public Filter Filter; - public string Filename; - public uint Offset; - } - - VMwareExtentHeader vmEHdr; - VMwareCowHeader vmCHdr; - - Dictionary<ulong, byte[]> sectorCache; - Dictionary<ulong, byte[]> grainCache; - - uint cid; - uint parentCid; - string imageType; - uint version; - Dictionary<ulong, VMwareExtent> extents; - string parentName; const uint MAX_CACHE_SIZE = 16777216; const uint SECTOR_SIZE = 512; const uint MAX_CACHED_SECTORS = MAX_CACHE_SIZE / SECTOR_SIZE; - uint maxCachedGrains; + readonly byte[] ddfMagicBytes = + { + 0x23, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6F, 0x72, 0x46, + 0x69, 0x6C, 0x65 + }; - ImagePlugin parentImage; - bool hasParent; + uint cid; + Dictionary<ulong, VMwareExtent> extents; Filter gdFilter; - uint[] gTable; + Dictionary<ulong, byte[]> grainCache; ulong grainSize; + uint[] gTable; + bool hasParent; + string imageType; + uint maxCachedGrains; + uint parentCid; + + ImagePlugin parentImage; + string parentName; + + Dictionary<ulong, byte[]> sectorCache; + uint version; + VMwareCowHeader vmCHdr; + + VMwareExtentHeader vmEHdr; public VMware() { @@ -388,15 +326,15 @@ namespace DiscImageChef.DiscImages { ddfStream.Seek(0, SeekOrigin.Begin); - Regex regexVersion = new Regex(VERSION_REGEX); - Regex regexCid = new Regex(CID_REGEX); - Regex regexParentCid = new Regex(PAREN_CID_REGEX); - Regex regexType = new Regex(TYPE_REGEX); - Regex regexExtent = new Regex(EXTENT_REGEX); + Regex regexVersion = new Regex(REGEX_VERSION); + Regex regexCid = new Regex(REGEX_CID); + Regex regexParentCid = new Regex(REGEX_CID_PARENT); + Regex regexType = new Regex(REGEX_TYPE); + Regex regexExtent = new Regex(REGEX_EXTENT); Regex regexParent = new Regex(PARENT_REGEX); - Regex regexCylinders = new Regex(DDB_CYLINDERS_REGEX); - Regex regexHeads = new Regex(DDB_HEADS_REGEX); - Regex regexSectors = new Regex(DDB_SECTORS_REGEX); + Regex regexCylinders = new Regex(REGEX_DDB_CYLINDERS); + Regex regexHeads = new Regex(REGEX_DDB_HEADS); + Regex regexSectors = new Regex(REGEX_DDB_SECTORS); StreamReader ddfStreamRdr = new StreamReader(ddfStream); @@ -501,16 +439,14 @@ namespace DiscImageChef.DiscImages case VMFS_TYPE_RAW: //"vmfsRaw"; throw new ImageNotSupportedException("Raw device image files are not supported, try accessing the device directly."); - default: - throw new ImageNotSupportedException($"Dunno how to handle \"{imageType}\" extents."); + default: throw new ImageNotSupportedException($"Dunno how to handle \"{imageType}\" extents."); } bool oneNoFlat = cowD; foreach(VMwareExtent extent in extents.Values) { - if(extent.Filter == null) - throw new Exception($"Extent file {extent.Filename} not found."); + if(extent.Filter == null) throw new Exception($"Extent file {extent.Filename} not found."); if(extent.Access == "NOACCESS") throw new Exception("Cannot access NOACCESS extents ;)."); @@ -519,8 +455,7 @@ namespace DiscImageChef.DiscImages Stream extentStream = extent.Filter.GetDataForkStream(); extentStream.Seek(0, SeekOrigin.Begin); - if(extentStream.Length < SECTOR_SIZE) - throw new Exception($"Extent {extent.Filename} is too small."); + if(extentStream.Length < SECTOR_SIZE) throw new Exception($"Extent {extent.Filename} is too small."); VMwareExtentHeader extentHdr = new VMwareExtentHeader(); byte[] extentHdrB = new byte[Marshal.SizeOf(extentHdr)]; @@ -590,7 +525,8 @@ namespace DiscImageChef.DiscImages gdEntries = grains / vmEHdr.GTEsPerGT; gtEsPerGt = vmEHdr.GTEsPerGT; - if((vmEHdr.flags & FLAGS_USE_REDUNDANT_TABLE) == FLAGS_USE_REDUNDANT_TABLE) gdOffset = (long)vmEHdr.rgdOffset; + if((vmEHdr.flags & FLAGS_USE_REDUNDANT_TABLE) == FLAGS_USE_REDUNDANT_TABLE) + gdOffset = (long)vmEHdr.rgdOffset; else gdOffset = (long)vmEHdr.gdOffset; } else if(oneNoFlat && cowD) @@ -668,8 +604,7 @@ namespace DiscImageChef.DiscImages parentImage = new VMware(); - if(!parentImage.OpenImage(parentFilter)) - throw new Exception($"Cannot open parent \"{parentName}\"."); + if(!parentImage.OpenImage(parentFilter)) throw new Exception($"Cannot open parent \"{parentName}\"."); } sectorCache = new Dictionary<ulong, byte[]>(); @@ -712,7 +647,8 @@ namespace DiscImageChef.DiscImages bool extentFound = false; ulong extentStartSector = 0; - foreach(KeyValuePair<ulong, VMwareExtent> kvp in extents.Where(kvp => sectorAddress >= kvp.Key)) { + foreach(KeyValuePair<ulong, VMwareExtent> kvp in extents.Where(kvp => sectorAddress >= kvp.Key)) + { currentExtent = kvp.Value; extentFound = true; extentStartSector = kvp.Key; @@ -724,7 +660,8 @@ namespace DiscImageChef.DiscImages Stream dataStream; - switch(currentExtent.Type) { + switch(currentExtent.Type) + { case "ZERO": sector = new byte[SECTOR_SIZE]; @@ -875,7 +812,6 @@ namespace DiscImageChef.DiscImages return ImageInfo.MediaType; } - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -1036,6 +972,64 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VMwareExtentHeader + { + public uint magic; + public uint version; + public uint flags; + public ulong capacity; + public ulong grainSize; + public ulong descriptorOffset; + public ulong descriptorSize; + public uint GTEsPerGT; + public ulong rgdOffset; + public ulong gdOffset; + public ulong overhead; + [MarshalAs(UnmanagedType.U1)] public bool uncleanShutdown; + public byte singleEndLineChar; + public byte nonEndLineChar; + public byte doubleEndLineChar1; + public byte doubleEndLineChar2; + public ushort compression; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 433)] public byte[] padding; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct VMwareCowHeader + { + public uint magic; + public uint version; + public uint flags; + public uint sectors; + public uint grainSize; + public uint gdOffset; + public uint numGDEntries; + public uint freeSector; + public uint cylinders; + public uint heads; + public uint spt; + // It stats on cylinders, above, but, don't care + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024 - 12)] public byte[] parentFileName; + public uint parentGeneration; + public uint generation; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] public byte[] name; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] public byte[] description; + public uint savedGeneration; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] reserved; + [MarshalAs(UnmanagedType.U1)] public bool uncleanShutdown; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 396)] public byte[] padding; + } + + struct VMwareExtent + { + public string Access; + public uint Sectors; + public string Type; + public Filter Filter; + public string Filename; + public uint Offset; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/Virtual98.cs b/DiscImageChef.DiscImages/Virtual98.cs index 0ea484fe7..b27d32178 100644 --- a/DiscImageChef.DiscImages/Virtual98.cs +++ b/DiscImageChef.DiscImages/Virtual98.cs @@ -45,24 +45,10 @@ namespace DiscImageChef.DiscImages // Info from Neko Project II emulator public class Virtual98 : ImagePlugin { - #region Internal structures - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct Virtual98Header - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] signature; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] comment; - public uint padding; - public ushort mbsize; - public ushort sectorsize; - public byte sectors; - public byte surfaces; - public ushort cylinders; - public uint totals; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x44)] public byte[] padding2; - } - #endregion - readonly byte[] signature = {0x56, 0x48, 0x44, 0x31, 0x2E, 0x30, 0x30, 0x00}; + Filter nhdImageFilter; + + Virtual98Header v98Hdr; public Virtual98() { @@ -93,9 +79,6 @@ namespace DiscImageChef.DiscImages }; } - Virtual98Header v98Hdr; - Filter nhdImageFilter; - public override bool IdentifyImage(Filter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); @@ -269,7 +252,6 @@ namespace DiscImageChef.DiscImages return buffer; } - #region Unsupported features public override byte[] ReadDiskTag(MediaTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -430,6 +412,20 @@ namespace DiscImageChef.DiscImages { return null; } - #endregion + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Virtual98Header + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] signature; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] comment; + public uint padding; + public ushort mbsize; + public ushort sectorsize; + public byte sectors; + public byte surfaces; + public ushort cylinders; + public uint totals; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x44)] public byte[] padding2; + } } } \ No newline at end of file diff --git a/DiscImageChef.DiscImages/ZZZRawImage.cs b/DiscImageChef.DiscImages/ZZZRawImage.cs index 9ef76a7b2..c93d4fb63 100644 --- a/DiscImageChef.DiscImages/ZZZRawImage.cs +++ b/DiscImageChef.DiscImages/ZZZRawImage.cs @@ -41,11 +41,9 @@ namespace DiscImageChef.DiscImages { public class ZZZRawImage : ImagePlugin { - #region Internal variables - Filter rawImageFilter; bool differentTrackZeroSize; string extension; - #endregion + Filter rawImageFilter; public ZZZRawImage() { @@ -122,10 +120,13 @@ namespace DiscImageChef.DiscImages stream.Seek(0, SeekOrigin.Begin); extension = Path.GetExtension(imageFilter.GetFilename())?.ToLower(); - switch(extension) { - case ".iso" when imageFilter.GetDataForkLength() % 2048 == 0: ImageInfo.SectorSize = 2048; + switch(extension) + { + case ".iso" when imageFilter.GetDataForkLength() % 2048 == 0: + ImageInfo.SectorSize = 2048; break; - case ".d81" when imageFilter.GetDataForkLength() == 819200: ImageInfo.SectorSize = 256; + case ".d81" when imageFilter.GetDataForkLength() == 819200: + ImageInfo.SectorSize = 256; break; default: if((extension == ".adf" || extension == ".adl" || extension == ".ssd" || extension == ".dsd") && @@ -892,7 +893,6 @@ namespace DiscImageChef.DiscImages return ReadSectors(sectorAddress, length); } - #region Private methods MediaType CalculateDiskType() { if(ImageInfo.SectorSize == 2048) @@ -903,9 +903,8 @@ namespace DiscImageChef.DiscImages if(ImageInfo.Sectors <= 4171712) return MediaType.DVDRDL; if(ImageInfo.Sectors <= 4173824) return MediaType.DVDPRDL; if(ImageInfo.Sectors <= 24438784) return MediaType.BDR; - if(ImageInfo.Sectors <= 62500864) return MediaType.BDRXL; - return MediaType.Unknown; + return ImageInfo.Sectors <= 62500864 ? MediaType.BDRXL : MediaType.Unknown; } switch(ImageInfo.ImageSize) @@ -1006,9 +1005,7 @@ namespace DiscImageChef.DiscImages default: return MediaType.GENERIC_HDD; } } - #endregion - #region Unsupported features public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); @@ -1137,6 +1134,5 @@ namespace DiscImageChef.DiscImages { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - #endregion Unsupported features } } \ No newline at end of file