diff --git a/DiscImageChef.DiscImages/CDRWin.cs b/DiscImageChef.DiscImages/CDRWin.cs index d5b4c4592..cb3b49a08 100644 --- a/DiscImageChef.DiscImages/CDRWin.cs +++ b/DiscImageChef.DiscImages/CDRWin.cs @@ -1799,8 +1799,8 @@ namespace DiscImageChef.ImagePlugins case CDRWinTrackTypeCDG: { sector_offset = 0; - sector_size = 2448; - sector_skip = 0; + sector_size = 2352; + sector_skip = 96; break; } default: @@ -1907,6 +1907,19 @@ namespace DiscImageChef.ImagePlugins _track.TrackSession = cdr_track.session; _track.TrackSequence = cdr_track.sequence; _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); + _track.TrackFile = cdr_track.trackfile.datafile; + _track.TrackFileOffset = cdr_track.trackfile.offset; + _track.TrackFileType = cdr_track.trackfile.filetype; + _track.TrackRawBytesPerSector = cdr_track.bps; + _track.TrackBytesPerSector = CDRWinTrackTypeToCookedBytesPerSector(cdr_track.tracktype); + if (cdr_track.bps == 2448) + { + _track.TrackSubchannelFile = cdr_track.trackfile.datafile; + _track.TrackSubchannelOffset = cdr_track.trackfile.offset; + _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; + } + else + _track.TrackSubchannelType = TrackSubchannelType.None; tracks.Add(_track); previousStartSector = _track.TrackEndSector + 1; @@ -1943,6 +1956,19 @@ namespace DiscImageChef.ImagePlugins _track.TrackSession = cdr_track.session; _track.TrackSequence = cdr_track.sequence; _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); + _track.TrackFile = cdr_track.trackfile.datafile; + _track.TrackFileOffset = cdr_track.trackfile.offset; + _track.TrackFileType = cdr_track.trackfile.filetype; + _track.TrackRawBytesPerSector = cdr_track.bps; + _track.TrackBytesPerSector = CDRWinTrackTypeToCookedBytesPerSector(cdr_track.tracktype); + if (cdr_track.bps == 2448) + { + _track.TrackSubchannelFile = cdr_track.trackfile.datafile; + _track.TrackSubchannelOffset = cdr_track.trackfile.offset; + _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; + } + else + _track.TrackSubchannelType = TrackSubchannelType.None; tracks.Add(_track); } @@ -2078,6 +2104,30 @@ namespace DiscImageChef.ImagePlugins } } + static UInt16 CDRWinTrackTypeToCookedBytesPerSector(string trackType) + { + switch (trackType) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode2Form1: + case CDRWinTrackTypeMode1Raw: + return 2048; + case CDRWinTrackTypeMode2Form2: + return 2324; + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeCDI: + case CDRWinTrackTypeMode2Raw: + case CDRWinTrackTypeCDIRaw: + return 2336; + case CDRWinTrackTypeAudio: + return 2352; + case CDRWinTrackTypeCDG: + return 2448; + default: + return 0; + } + } + static TrackType CDRWinTrackTypeToTrackType(string trackType) { switch (trackType) diff --git a/DiscImageChef.DiscImages/ChangeLog b/DiscImageChef.DiscImages/ChangeLog index 502709277..1f45d6662 100644 --- a/DiscImageChef.DiscImages/ChangeLog +++ b/DiscImageChef.DiscImages/ChangeLog @@ -1,3 +1,21 @@ +2015-12-06 Natalia Portillo + + * CDRWin.cs: + Added extra track information. + Corrected ReadLong for CD+G, subchannel should never come + along main channel on reading. + + * ImagePlugin.cs: + Added extra track information. + Added audio media type. + + * Nero.cs: + Added extra track information. + + * ZZZRawImage.cs: + Added support for ReadLong and a single track and session + for optical discs. + 2015-12-05 Natalia Portillo * VHD.cs: diff --git a/DiscImageChef.DiscImages/ImagePlugin.cs b/DiscImageChef.DiscImages/ImagePlugin.cs index bdac0cd85..bf9714cd5 100644 --- a/DiscImageChef.DiscImages/ImagePlugin.cs +++ b/DiscImageChef.DiscImages/ImagePlugin.cs @@ -467,6 +467,23 @@ namespace DiscImageChef.ImagePlugins public string TrackDescription; /// Indexes, 00 to 99 and sector offset public Dictionary Indexes; + public string TrackFile; + public ulong TrackFileOffset; + public string TrackFileType; + public int TrackBytesPerSector; + public int TrackRawBytesPerSector; + public string TrackSubchannelFile; + public ulong TrackSubchannelOffset; + public TrackSubchannelType TrackSubchannelType; + } + + public enum TrackSubchannelType + { + None, + Packed, + Raw, + PackedInterleaved, + RawInterleaved } /// @@ -626,7 +643,8 @@ namespace DiscImageChef.ImagePlugins { OpticalDisc, BlockMedia, - LinearMedia + LinearMedia, + AudioMedia } /// diff --git a/DiscImageChef.DiscImages/Nero.cs b/DiscImageChef.DiscImages/Nero.cs index 453d6e875..e9b0addba 100644 --- a/DiscImageChef.DiscImages/Nero.cs +++ b/DiscImageChef.DiscImages/Nero.cs @@ -1533,6 +1533,55 @@ namespace DiscImageChef.ImagePlugins _track.TrackStartSector = _neroTrack.StartLBA; _track.TrackType = NeroTrackModeToTrackType((DAOMode)_neroTrack.Mode); imageTracks.Add(_track); + _track.TrackFile = _imagePath; + _track.TrackFileOffset = _neroTrack.Offset; + _track.TrackFileType = "BINARY"; + _track.TrackSubchannelType = TrackSubchannelType.None; + switch((DAOMode)_neroTrack.Mode) + { + case DAOMode.Audio: + _track.TrackBytesPerSector = 2352; + _track.TrackRawBytesPerSector = 2352; + break; + case DAOMode.AudioSub: + _track.TrackBytesPerSector = 2352; + _track.TrackRawBytesPerSector = 2448; + _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; + break; + case DAOMode.Data: + case DAOMode.DataM2F1: + _track.TrackBytesPerSector = 2048; + _track.TrackRawBytesPerSector = 2048; + break; + case DAOMode.DataM2F2: + _track.TrackBytesPerSector = 2336; + _track.TrackRawBytesPerSector = 2336; + break; + case DAOMode.DataM2Raw: + _track.TrackBytesPerSector = 2352; + _track.TrackRawBytesPerSector = 2352; + break; + case DAOMode.DataM2RawSub: + _track.TrackBytesPerSector = 2352; + _track.TrackRawBytesPerSector = 2448; + _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; + break; + case DAOMode.DataRaw: + _track.TrackBytesPerSector = 2048; + _track.TrackRawBytesPerSector = 2352; + break; + case DAOMode.DataRawSub: + _track.TrackBytesPerSector = 2048; + _track.TrackRawBytesPerSector = 2448; + _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; + break; + } + + if(_track.TrackSubchannelType == TrackSubchannelType.RawInterleaved) + { + _track.TrackSubchannelFile = _imagePath; + _track.TrackSubchannelOffset = _neroTrack.Offset; + } DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackDescription = {0}", _track.TrackDescription); DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackEndSector = {0}", _track.TrackEndSector); diff --git a/DiscImageChef.DiscImages/ZZZRawImage.cs b/DiscImageChef.DiscImages/ZZZRawImage.cs index 86749bd8e..82d633e2c 100644 --- a/DiscImageChef.DiscImages/ZZZRawImage.cs +++ b/DiscImageChef.DiscImages/ZZZRawImage.cs @@ -398,6 +398,154 @@ namespace DiscImageChef.ImagePlugins return null; } + public override List GetTracks() + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + Track trk = new Track(); + trk.TrackBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackEndSector = ImageInfo.sectors - 1; + trk.TrackFile = rawImagePath; + trk.TrackFileOffset = 0; + trk.TrackFileType = "BINARY"; + trk.TrackRawBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackSequence = 1; + trk.TrackStartSector = 0; + trk.TrackSubchannelType = TrackSubchannelType.None; + trk.TrackType = TrackType.Data; + trk.TrackSession = 1; + List lst = new List(); + lst.Add(trk); + return lst; + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessionTracks(Session session) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (session.SessionSequence != 1) + throw new ArgumentOutOfRangeException("session", "Only a single session is supported"); + + Track trk = new Track(); + trk.TrackBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackEndSector = ImageInfo.sectors - 1; + trk.TrackFile = rawImagePath; + trk.TrackFileOffset = 0; + trk.TrackFileType = "BINARY"; + trk.TrackRawBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackSequence = 1; + trk.TrackStartSector = 0; + trk.TrackSubchannelType = TrackSubchannelType.None; + trk.TrackType = TrackType.Data; + trk.TrackSession = 1; + List lst = new List(); + lst.Add(trk); + return lst; + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessionTracks(UInt16 session) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (session != 1) + throw new ArgumentOutOfRangeException("session", "Only a single session is supported"); + + Track trk = new Track(); + trk.TrackBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackEndSector = ImageInfo.sectors - 1; + trk.TrackFile = rawImagePath; + trk.TrackFileOffset = 0; + trk.TrackFileType = "BINARY"; + trk.TrackRawBytesPerSector = (int)ImageInfo.sectorSize; + trk.TrackSequence = 1; + trk.TrackStartSector = 0; + trk.TrackSubchannelType = TrackSubchannelType.None; + trk.TrackType = TrackType.Data; + trk.TrackSession = 1; + List lst = new List(); + lst.Add(trk); + return lst; + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override List GetSessions() + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + Session sess = new Session(); + sess.EndSector = ImageInfo.sectors - 1; + sess.EndTrack = 1; + sess.SessionSequence = 1; + sess.StartSector = 0; + sess.StartTrack = 1; + List lst = new List(); + lst.Add(sess); + return lst; + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (track != 1) + throw new ArgumentOutOfRangeException("track", "Only a single session is supported"); + + return ReadSector(sectorAddress); + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (track != 1) + throw new ArgumentOutOfRangeException("track", "Only a single session is supported"); + + return ReadSectors(sectorAddress, length); + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (track != 1) + throw new ArgumentOutOfRangeException("track", "Only a single session is supported"); + + return ReadSector(sectorAddress); + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + + public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track) + { + if (ImageInfo.xmlMediaType == XmlMediaType.OpticalDisc) + { + if (track != 1) + throw new ArgumentOutOfRangeException("track", "Only a single session is supported"); + + return ReadSectors(sectorAddress, length); + } + + throw new FeatureUnsupportedImageException("Feature not supported by image format"); + } + #region Private methods DiskType CalculateDiskType() @@ -645,56 +793,16 @@ namespace DiscImageChef.ImagePlugins throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - public override List GetTracks() - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - - public override List GetSessionTracks(Session session) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - - public override List GetSessionTracks(UInt16 session) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - - public override List GetSessions() - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - - public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - public override byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag) { throw new FeatureUnsupportedImageException("Feature not supported by image format"); } - public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - - public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track) - { - throw new FeatureUnsupportedImageException("Feature not supported by image format"); - } - #endregion Unsupported features } } diff --git a/DiscImageChef.Filesystems/AmigaDOS.cs b/DiscImageChef.Filesystems/AmigaDOS.cs index a8b9a011e..846b43a44 100644 --- a/DiscImageChef.Filesystems/AmigaDOS.cs +++ b/DiscImageChef.Filesystems/AmigaDOS.cs @@ -355,8 +355,12 @@ namespace DiscImageChef.Plugins information = sbInformation.ToString(); xmlFSType.CreationDate = DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks); + xmlFSType.CreationDateSpecified = true; xmlFSType.ModificationDate = DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks); + xmlFSType.ModificationDateSpecified = true; xmlFSType.Dirty = rootBlk.bitmapFlag != 0xFFFFFFFF; + xmlFSType.Clusters = (long)((partitionEnd - partitionStart) + 1); + xmlFSType.ClusterSize = (int)imagePlugin.GetSectorSize(); } static UInt32 AmigaChecksum(byte[] data) diff --git a/DiscImageChef.Filesystems/AppleHFS.cs b/DiscImageChef.Filesystems/AppleHFS.cs index 28d41f040..e60daf7b7 100644 --- a/DiscImageChef.Filesystems/AppleHFS.cs +++ b/DiscImageChef.Filesystems/AppleHFS.cs @@ -361,15 +361,29 @@ namespace DiscImageChef.Plugins information = sb.ToString(); xmlFSType = new Schemas.FileSystemType(); - xmlFSType.BackupDate = DateHandlers.MacToDateTime(MDB.drVolBkUp); + if (MDB.drVolBkUp > 0) + { + xmlFSType.BackupDate = DateHandlers.MacToDateTime(MDB.drVolBkUp); + xmlFSType.BackupDateSpecified = true; + } xmlFSType.Bootable = BB.signature == HFSBB_MAGIC; xmlFSType.Clusters = MDB.drNmAlBlks; xmlFSType.ClusterSize = (int)MDB.drAlBlkSiz; - xmlFSType.CreationDate = DateHandlers.MacToDateTime(MDB.drCrDate); + if (MDB.drCrDate > 0) + { + xmlFSType.CreationDate = DateHandlers.MacToDateTime(MDB.drCrDate); + xmlFSType.CreationDateSpecified = true; + } xmlFSType.Dirty = (MDB.drAtrb & 0x100) != 0x100; xmlFSType.Files = MDB.drFilCnt; + xmlFSType.FilesSpecified = true; xmlFSType.FreeClusters = MDB.drFreeBks; - xmlFSType.ModificationDate = DateHandlers.MacToDateTime(MDB.drLsMod); + xmlFSType.FreeClustersSpecified = true; + if (MDB.drLsMod > 0) + { + xmlFSType.ModificationDate = DateHandlers.MacToDateTime(MDB.drLsMod); + xmlFSType.ModificationDateSpecified = true; + } xmlFSType.Type = "HFS"; xmlFSType.VolumeName = MDB.drVN; if (MDB.drFndrInfo6 != 0 && MDB.drFndrInfo7 != 0) diff --git a/DiscImageChef.Filesystems/AppleHFSPlus.cs b/DiscImageChef.Filesystems/AppleHFSPlus.cs index b4c9a2f55..cc405d15d 100644 --- a/DiscImageChef.Filesystems/AppleHFSPlus.cs +++ b/DiscImageChef.Filesystems/AppleHFSPlus.cs @@ -258,16 +258,30 @@ namespace DiscImageChef.Plugins sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", HPVH.drFndrInfo6, HPVH.drFndrInfo7).AppendLine(); xmlFSType = new Schemas.FileSystemType(); - xmlFSType.BackupDate = DateHandlers.MacToDateTime(HPVH.backupDate); + if (HPVH.backupDate > 0) + { + xmlFSType.BackupDate = DateHandlers.MacToDateTime(HPVH.backupDate); + xmlFSType.BackupDateSpecified = true; + } if(HPVH.drFndrInfo0 != 0 || HPVH.drFndrInfo3 != 0 || HPVH.drFndrInfo5 != 0) xmlFSType.Bootable = true; xmlFSType.Clusters = HPVH.totalBlocks; xmlFSType.ClusterSize = (int)HPVH.blockSize; - xmlFSType.CreationDate = DateHandlers.MacToDateTime(HPVH.createDate); + if (HPVH.createDate > 0) + { + xmlFSType.CreationDate = DateHandlers.MacToDateTime(HPVH.createDate); + xmlFSType.CreationDateSpecified = true; + } xmlFSType.Dirty = (HPVH.attributes & 0x100) != 0x100; xmlFSType.Files = HPVH.fileCount; + xmlFSType.FilesSpecified = true; xmlFSType.FreeClusters = HPVH.freeBlocks; - xmlFSType.ModificationDate = DateHandlers.MacToDateTime(HPVH.modifyDate); + xmlFSType.FreeClustersSpecified = true; + if (HPVH.modifyDate > 0) + { + xmlFSType.ModificationDate = DateHandlers.MacToDateTime(HPVH.modifyDate); + xmlFSType.ModificationDateSpecified = true; + } if(HPVH.signature == 0x482B) xmlFSType.Type = "HFS+"; if(HPVH.signature == 0x4858) diff --git a/DiscImageChef.Filesystems/AppleMFS.cs b/DiscImageChef.Filesystems/AppleMFS.cs index 53b2a1150..27587d295 100644 --- a/DiscImageChef.Filesystems/AppleMFS.cs +++ b/DiscImageChef.Filesystems/AppleMFS.cs @@ -197,13 +197,23 @@ namespace DiscImageChef.Plugins information = sb.ToString(); xmlFSType = new Schemas.FileSystemType(); - xmlFSType.BackupDate = DateHandlers.MacToDateTime(MDB.drLsBkUp); + if (MDB.drLsBkUp > 0) + { + xmlFSType.BackupDate = DateHandlers.MacToDateTime(MDB.drLsBkUp); + xmlFSType.BackupDateSpecified = true; + } xmlFSType.Bootable = BB.signature == MFSBB_MAGIC; xmlFSType.Clusters = MDB.drNmAlBlks; xmlFSType.ClusterSize = (int)MDB.drAlBlkSiz; - xmlFSType.CreationDate = DateHandlers.MacToDateTime(MDB.drCrDate); + if (MDB.drCrDate > 0) + { + xmlFSType.CreationDate = DateHandlers.MacToDateTime(MDB.drCrDate); + xmlFSType.CreationDateSpecified = true; + } xmlFSType.Files = MDB.drNmFls; + xmlFSType.FilesSpecified = true; xmlFSType.FreeClusters = MDB.drFreeBks; + xmlFSType.FreeClustersSpecified = true; xmlFSType.Type = "MFS"; xmlFSType.VolumeName = MDB.drVN; diff --git a/DiscImageChef.Filesystems/BFS.cs b/DiscImageChef.Filesystems/BFS.cs index 4658aea2a..114686c4d 100644 --- a/DiscImageChef.Filesystems/BFS.cs +++ b/DiscImageChef.Filesystems/BFS.cs @@ -225,6 +225,7 @@ namespace DiscImageChef.Plugins xmlFSType.ClusterSize = (int)besb.block_size; xmlFSType.Dirty = besb.flags == BEFS_DIRTY; xmlFSType.FreeClusters = besb.num_blocks - besb.used_blocks; + xmlFSType.FreeClustersSpecified = true; xmlFSType.Type = "BeFS"; xmlFSType.VolumeName = besb.name; } diff --git a/DiscImageChef.Filesystems/ChangeLog b/DiscImageChef.Filesystems/ChangeLog index 97b9cf4a3..97764bd1e 100644 --- a/DiscImageChef.Filesystems/ChangeLog +++ b/DiscImageChef.Filesystems/ChangeLog @@ -1,3 +1,28 @@ +2015-12-06 Natalia Portillo + + * FFS.cs: + * BFS.cs: + * ODS.cs: + * SysV.cs: + * extFS.cs: + * ProDOS.cs: + * ext2FS.cs: + * LisaFS.cs: + * MinixFS.cs: + * UNIXBFS.cs: + * AppleMFS.cs: + * PCEngine.cs: + * AppleHFS.cs: + * AmigaDOS.cs: + * AppleHFSPlus.cs: + Completed XML information. + + * ISO9660.cs: + Corrected fail in Sega CD IP.BIN decoding. + Corrected IP.BIN date decoding. + Trim spaces at end of Volume Descriptor string fields. + Completed XML information. + 2015-12-05 Natalia Portillo * FAT.cs: diff --git a/DiscImageChef.Filesystems/FFS.cs b/DiscImageChef.Filesystems/FFS.cs index 0e6eca214..6eb44dc67 100644 --- a/DiscImageChef.Filesystems/FFS.cs +++ b/DiscImageChef.Filesystems/FFS.cs @@ -651,6 +651,7 @@ namespace DiscImageChef.Plugins sbInformation.AppendFormat("{0} directories", ufs_sb.fs_cstotal_ndir).AppendLine(); sbInformation.AppendFormat("{0} free blocks ({1} bytes)", ufs_sb.fs_cstotal_nbfree, ufs_sb.fs_cstotal_nbfree * ufs_sb.fs_bsize).AppendLine(); xmlFSType.FreeClusters = ufs_sb.fs_cstotal_nbfree; + xmlFSType.FreeClustersSpecified = true; sbInformation.AppendFormat("{0} free inodes", ufs_sb.fs_cstotal_nifree).AppendLine(); sbInformation.AppendFormat("{0} free frags", ufs_sb.fs_cstotal_nffree).AppendLine(); if (ufs_sb.fs_fmod == 1) @@ -681,11 +682,13 @@ namespace DiscImageChef.Plugins sbInformation.AppendFormat("{0} directories", ufs_sb.fs_cstotal_ndir_ufs2).AppendLine(); sbInformation.AppendFormat("{0} free blocks ({1} bytes)", ufs_sb.fs_cstotal_nbfree_ufs2, ufs_sb.fs_cstotal_nbfree_ufs2 * ufs_sb.fs_bsize).AppendLine(); xmlFSType.FreeClusters = (long)ufs_sb.fs_cstotal_nbfree_ufs2; + xmlFSType.FreeClustersSpecified = true; sbInformation.AppendFormat("{0} free inodes", ufs_sb.fs_cstotal_nifree_ufs2).AppendLine(); sbInformation.AppendFormat("{0} free frags", ufs_sb.fs_cstotal_nffree_ufs2).AppendLine(); sbInformation.AppendFormat("{0} free clusters", ufs_sb.fs_cstotal_numclusters_ufs2).AppendLine(); sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UNIXUnsignedToDateTime(ufs_sb.fs_time_sec_ufs2)).AppendLine(); xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(ufs_sb.fs_time_sec_ufs2); + xmlFSType.ModificationDateSpecified = true; sbInformation.AppendFormat("{0} blocks ({1} bytes)", ufs_sb.fs_size_ufs2, ufs_sb.fs_size_ufs2 * ufs_sb.fs_bsize).AppendLine(); xmlFSType.Clusters = (long)ufs_sb.fs_dsize_ufs2; sbInformation.AppendFormat("{0} data blocks ({1} bytes)", ufs_sb.fs_dsize_ufs2, ufs_sb.fs_dsize_ufs2 * ufs_sb.fs_bsize).AppendLine(); diff --git a/DiscImageChef.Filesystems/ISO9660.cs b/DiscImageChef.Filesystems/ISO9660.cs index eca650a07..d178905ad 100644 --- a/DiscImageChef.Filesystems/ISO9660.cs +++ b/DiscImageChef.Filesystems/ISO9660.cs @@ -393,8 +393,8 @@ namespace DiscImageChef.Plugins DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_name = \"{0}\"", Encoding.ASCII.GetString(volume_name)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_name = \"{0}\"", Encoding.ASCII.GetString(system_name)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_version = \"{0}\"", Encoding.ASCII.GetString(volume_version)); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_type = 0x{0}", BitConverter.ToInt32(volume_type, 0).ToString("X")); - DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_version = 0x{0}", BitConverter.ToInt32(system_version, 0).ToString("X")); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.volume_type = 0x{0}", BitConverter.ToInt16(volume_type, 0).ToString("X")); + DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.system_version = 0x{0}", BitConverter.ToInt16(system_version, 0).ToString("X")); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_address = 0x{0}", BitConverter.ToInt32(ip_address, 0).ToString("X")); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_loadsize = {0}", BitConverter.ToInt32(ip_loadsize, 0)); DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.ip_entry_address = 0x{0}", BitConverter.ToInt32(ip_entry_address, 0).ToString("X")); @@ -413,9 +413,20 @@ namespace DiscImageChef.Plugins DicConsole.DebugWriteLine("ISO9660 plugin", "segacd_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(region_codes)); // Decoding all data - DateTime ipbindate; + DateTime ipbindate = DateTime.MinValue; CultureInfo provider = CultureInfo.InvariantCulture; - ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "MMddyyyy", provider); + try + { + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "MMddyyyy", provider); + } + catch + { + try + { + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date2), "yyyy.MMM", provider); + } + catch {} + } /* switch (Encoding.ASCII.GetString(application_type)) @@ -445,8 +456,9 @@ namespace DiscImageChef.Plugins IPBinInformation.AppendFormat("System program load size: {0} bytes", BitConverter.ToInt32(sp_loadsize, 0)).AppendLine(); IPBinInformation.AppendFormat("System program entry address: 0x{0}", BitConverter.ToInt32(sp_entry_address, 0).ToString("X")).AppendLine(); IPBinInformation.AppendFormat("System program work RAM: {0} bytes", BitConverter.ToInt32(sp_work_ram_size, 0)).AppendLine(); - IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); - IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); + if(ipbindate != DateTime.MinValue) + IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); + //IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); IPBinInformation.AppendFormat("Hardware ID: {0}", Encoding.ASCII.GetString(hardware_id)).AppendLine(); IPBinInformation.AppendFormat("Developer code: {0}", Encoding.ASCII.GetString(developer_code)).AppendLine(); IPBinInformation.AppendFormat("Domestic title: {0}", Encoding.ASCII.GetString(domestic_title)).AppendLine(); @@ -879,7 +891,59 @@ namespace DiscImageChef.Plugins if (Joliet) { xmlFSType.SystemIdentifier = decodedJolietVD.SystemIdentifier; + xmlFSType.VolumeName = decodedJolietVD.VolumeIdentifier; + xmlFSType.VolumeSetIdentifier = decodedJolietVD.VolumeSetIdentifier; + xmlFSType.PublisherIdentifier = decodedJolietVD.PublisherIdentifier; + xmlFSType.DataPreparerIdentifier = decodedJolietVD.DataPreparerIdentifier; + xmlFSType.ApplicationIdentifier = decodedJolietVD.ApplicationIdentifier; + xmlFSType.CreationDate = decodedJolietVD.CreationTime; + xmlFSType.CreationDateSpecified = true; + if (decodedJolietVD.HasModificationTime) + { + xmlFSType.ModificationDate = decodedJolietVD.ModificationTime; + xmlFSType.ModificationDateSpecified = true; + } + if (decodedJolietVD.HasExpirationTime) + { + xmlFSType.ExpirationDate = decodedJolietVD.ExpirationTime; + xmlFSType.ExpirationDateSpecified = true; + } + if (decodedJolietVD.HasEffectiveTime) + { + xmlFSType.EffectiveDate = decodedJolietVD.EffectiveTime; + xmlFSType.EffectiveDateSpecified = true; + } } + else + { + xmlFSType.SystemIdentifier = decodedVD.SystemIdentifier; + xmlFSType.VolumeName = decodedVD.VolumeIdentifier; + xmlFSType.VolumeSetIdentifier = decodedVD.VolumeSetIdentifier; + xmlFSType.PublisherIdentifier = decodedVD.PublisherIdentifier; + xmlFSType.DataPreparerIdentifier = decodedVD.DataPreparerIdentifier; + xmlFSType.ApplicationIdentifier = decodedVD.ApplicationIdentifier; + xmlFSType.CreationDate = decodedVD.CreationTime; + xmlFSType.CreationDateSpecified = true; + if (decodedVD.HasModificationTime) + { + xmlFSType.ModificationDate = decodedVD.ModificationTime; + xmlFSType.ModificationDateSpecified = true; + } + if (decodedVD.HasExpirationTime) + { + xmlFSType.ExpirationDate = decodedVD.ExpirationTime; + xmlFSType.ExpirationDateSpecified = true; + } + if (decodedVD.HasEffectiveTime) + { + xmlFSType.EffectiveDate = decodedVD.EffectiveTime; + xmlFSType.EffectiveDateSpecified = true; + } + } + + xmlFSType.Bootable |= Bootable || SegaCD || Saturn || Dreamcast; + xmlFSType.Clusters = (long)(partitionEnd - partitionStart + 1); + xmlFSType.ClusterSize = 2048; information = ISOMetadata.ToString(); } @@ -888,12 +952,12 @@ namespace DiscImageChef.Plugins { DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor(); - decodedVD.SystemIdentifier = Encoding.BigEndianUnicode.GetString(VDSysId); - decodedVD.VolumeIdentifier = Encoding.BigEndianUnicode.GetString(VDVolId); - decodedVD.VolumeSetIdentifier = Encoding.BigEndianUnicode.GetString(VDVolSetId); - decodedVD.PublisherIdentifier = Encoding.BigEndianUnicode.GetString(VDPubId); - decodedVD.DataPreparerIdentifier = Encoding.BigEndianUnicode.GetString(VDDataPrepId); - decodedVD.ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(VDAppId); + decodedVD.SystemIdentifier = Encoding.BigEndianUnicode.GetString(VDSysId).TrimEnd(); + decodedVD.VolumeIdentifier = Encoding.BigEndianUnicode.GetString(VDVolId).TrimEnd(); + decodedVD.VolumeSetIdentifier = Encoding.BigEndianUnicode.GetString(VDVolSetId).TrimEnd(); + decodedVD.PublisherIdentifier = Encoding.BigEndianUnicode.GetString(VDPubId).TrimEnd(); + decodedVD.DataPreparerIdentifier = Encoding.BigEndianUnicode.GetString(VDDataPrepId).TrimEnd(); + decodedVD.ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(VDAppId).TrimEnd(); if (VCTime[0] == '0' || VCTime[0] == 0x00) decodedVD.CreationTime = DateTime.MinValue; else @@ -936,12 +1000,12 @@ namespace DiscImageChef.Plugins { DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor(); - decodedVD.SystemIdentifier = Encoding.ASCII.GetString(VDSysId); - decodedVD.VolumeIdentifier = Encoding.ASCII.GetString(VDVolId); - decodedVD.VolumeSetIdentifier = Encoding.ASCII.GetString(VDVolSetId); - decodedVD.PublisherIdentifier = Encoding.ASCII.GetString(VDPubId); - decodedVD.DataPreparerIdentifier = Encoding.ASCII.GetString(VDDataPrepId); - decodedVD.ApplicationIdentifier = Encoding.ASCII.GetString(VDAppId); + decodedVD.SystemIdentifier = Encoding.ASCII.GetString(VDSysId).TrimEnd(); + decodedVD.VolumeIdentifier = Encoding.ASCII.GetString(VDVolId).TrimEnd(); + decodedVD.VolumeSetIdentifier = Encoding.ASCII.GetString(VDVolSetId).TrimEnd(); + decodedVD.PublisherIdentifier = Encoding.ASCII.GetString(VDPubId).TrimEnd(); + decodedVD.DataPreparerIdentifier = Encoding.ASCII.GetString(VDDataPrepId).TrimEnd(); + decodedVD.ApplicationIdentifier = Encoding.ASCII.GetString(VDAppId).TrimEnd(); if (VCTime[0] == '0' || VCTime[0] == 0x00) decodedVD.CreationTime = DateTime.MinValue; else diff --git a/DiscImageChef.Filesystems/LisaFS.cs b/DiscImageChef.Filesystems/LisaFS.cs index 00cdc2974..e7ece8d01 100644 --- a/DiscImageChef.Filesystems/LisaFS.cs +++ b/DiscImageChef.Filesystems/LisaFS.cs @@ -387,13 +387,23 @@ namespace DiscImageChef.Plugins information = sb.ToString(); xmlFSType = new Schemas.FileSystemType(); - xmlFSType.BackupDate = mddf.dtvb; + if(DateTime.Compare(mddf.dtvb, DateHandlers.LisaToDateTime(0)) > 0) + { + xmlFSType.BackupDate = mddf.dtvb; + xmlFSType.BackupDateSpecified = true; + } xmlFSType.Clusters = mddf.vol_size; xmlFSType.ClusterSize = mddf.clustersize * mddf.datasize; - xmlFSType.CreationDate = mddf.dtvc; + if(DateTime.Compare(mddf.dtvc, DateHandlers.LisaToDateTime(0)) > 0) + { + xmlFSType.CreationDate = mddf.dtvc; + xmlFSType.CreationDateSpecified = true; + } xmlFSType.Dirty = mddf.vol_left_mounted != 0; xmlFSType.Files = mddf.filecount; + xmlFSType.FilesSpecified = true; xmlFSType.FreeClusters = mddf.freecount; + xmlFSType.FreeClustersSpecified = true; xmlFSType.Type = "LisaFS"; xmlFSType.VolumeName = mddf.volname; xmlFSType.VolumeSerial = String.Format("{0:X16}", mddf.volid); diff --git a/DiscImageChef.Filesystems/MinixFS.cs b/DiscImageChef.Filesystems/MinixFS.cs index 1932a0db6..d8eb05804 100644 --- a/DiscImageChef.Filesystems/MinixFS.cs +++ b/DiscImageChef.Filesystems/MinixFS.cs @@ -209,6 +209,7 @@ namespace DiscImageChef.Plugins sb.AppendFormat("On-disk filesystem version: {0}", mnx_sb.s_disk_version).AppendLine(); xmlFSType.ClusterSize = mnx_sb.s_blocksize; + xmlFSType.Clusters = (long)((partitionEnd - partitionStart + 1) * imagePlugin.GetSectorSize() / mnx_sb.s_blocksize); } else { @@ -239,6 +240,7 @@ namespace DiscImageChef.Plugins sb.AppendFormat("{0} bytes maximum per file", mnx_sb.s_max_size).AppendLine(); sb.AppendFormat("Filesystem state: {0:X4}", mnx_sb.s_state).AppendLine(); xmlFSType.ClusterSize = 1024; + xmlFSType.Clusters = (long)((partitionEnd - partitionStart + 1) * imagePlugin.GetSectorSize() / 1024); } information = sb.ToString(); } diff --git a/DiscImageChef.Filesystems/ODS.cs b/DiscImageChef.Filesystems/ODS.cs index 8cc49a186..174cc0a1d 100644 --- a/DiscImageChef.Filesystems/ODS.cs +++ b/DiscImageChef.Filesystems/ODS.cs @@ -260,11 +260,19 @@ namespace DiscImageChef.Plugins xmlFSType = new Schemas.FileSystemType(); xmlFSType.Type = "FILES-11"; xmlFSType.ClusterSize = homeblock.cluster * 512; + xmlFSType.Clusters = homeblock.cluster; xmlFSType.VolumeName = homeblock.volname; xmlFSType.VolumeSerial = String.Format("{0:X8}", homeblock.serialnum); - xmlFSType.CreationDate = DateHandlers.VMSToDateTime(homeblock.credate); + if (homeblock.credate > 0) + { + xmlFSType.CreationDate = DateHandlers.VMSToDateTime(homeblock.credate); + xmlFSType.CreationDateSpecified = true; + } if (homeblock.revdate > 0) + { xmlFSType.ModificationDate = DateHandlers.VMSToDateTime(homeblock.revdate); + xmlFSType.ModificationDateSpecified = true; + } information = sb.ToString(); } diff --git a/DiscImageChef.Filesystems/PCEngine.cs b/DiscImageChef.Filesystems/PCEngine.cs index fffab0fc6..71c0ce3d7 100644 --- a/DiscImageChef.Filesystems/PCEngine.cs +++ b/DiscImageChef.Filesystems/PCEngine.cs @@ -68,6 +68,8 @@ namespace DiscImageChef.Plugins information = ""; xmlFSType = new Schemas.FileSystemType(); xmlFSType.Type = "PC Engine filesystem"; + xmlFSType.Clusters = (long)((partitionEnd - partitionStart + 1) / imagePlugin.GetSectorSize() * 2048); + xmlFSType.ClusterSize = 2048; } } } \ No newline at end of file diff --git a/DiscImageChef.Filesystems/ProDOS.cs b/DiscImageChef.Filesystems/ProDOS.cs index 6004c7bf1..f2c55fcb7 100644 --- a/DiscImageChef.Filesystems/ProDOS.cs +++ b/DiscImageChef.Filesystems/ProDOS.cs @@ -219,9 +219,15 @@ namespace DiscImageChef.Plugins xmlFSType = new Schemas.FileSystemType(); xmlFSType.VolumeName = rootDirectoryKeyBlock.header.volume_name; - xmlFSType.CreationDate = rootDirectoryKeyBlock.header.creation_time; + if (year != 0 || month != 0 || day != 0 || hour != 0 || minute != 0) + { + xmlFSType.CreationDate = rootDirectoryKeyBlock.header.creation_time; + xmlFSType.CreationDateSpecified = true; + } xmlFSType.Files = rootDirectoryKeyBlock.header.file_count; + xmlFSType.FilesSpecified = true; xmlFSType.Clusters = rootDirectoryKeyBlock.header.total_blocks; + xmlFSType.ClusterSize = (int)((partitionEnd - partitionStart + 1) / (ulong)xmlFSType.Clusters); xmlFSType.Type = "ProDOS"; return; diff --git a/DiscImageChef.Filesystems/SysV.cs b/DiscImageChef.Filesystems/SysV.cs index e3debbbbf..900333eeb 100644 --- a/DiscImageChef.Filesystems/SysV.cs +++ b/DiscImageChef.Filesystems/SysV.cs @@ -343,7 +343,11 @@ namespace DiscImageChef.Plugins if (xnx_sb.s_ronly > 0) sb.AppendLine("Volume is mounted read-only"); sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(xnx_sb.s_time)).AppendLine(); - xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(xnx_sb.s_time); + if (xnx_sb.s_time != 0) + { + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(xnx_sb.s_time); + xmlFSType.ModificationDateSpecified = true; + } sb.AppendFormat("Volume name: {0}", xnx_sb.s_fname).AppendLine(); xmlFSType.VolumeName = xnx_sb.s_fname; sb.AppendFormat("Pack name: {0}", xnx_sb.s_fpack).AppendLine(); @@ -478,7 +482,11 @@ namespace DiscImageChef.Plugins if (sysv_sb.s_ronly > 0) sb.AppendLine("Volume is mounted read-only"); sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(sysv_sb.s_time)).AppendLine(); - xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(sysv_sb.s_time); + if (sysv_sb.s_time != 0) + { + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(sysv_sb.s_time); + xmlFSType.ModificationDateSpecified = true; + } sb.AppendFormat("Volume name: {0}", sysv_sb.s_fname).AppendLine(); xmlFSType.VolumeName = sysv_sb.s_fname; sb.AppendFormat("Pack name: {0}", sysv_sb.s_fpack).AppendLine(); @@ -536,7 +544,11 @@ namespace DiscImageChef.Plugins if (coh_sb.s_ronly > 0) sb.AppendLine("Volume is mounted read-only"); sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(coh_sb.s_time)).AppendLine(); - xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(coh_sb.s_time); + if (coh_sb.s_time != 0) + { + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(coh_sb.s_time); + xmlFSType.ModificationDateSpecified = true; + } sb.AppendFormat("Volume name: {0}", coh_sb.s_fname).AppendLine(); xmlFSType.VolumeName = coh_sb.s_fname; sb.AppendFormat("Pack name: {0}", coh_sb.s_fpack).AppendLine(); @@ -586,7 +598,11 @@ namespace DiscImageChef.Plugins if (v7_sb.s_ronly > 0) sb.AppendLine("Volume is mounted read-only"); sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(v7_sb.s_time)).AppendLine(); - xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(v7_sb.s_time); + if (v7_sb.s_time != 0) + { + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(v7_sb.s_time); + xmlFSType.ModificationDateSpecified = true; + } sb.AppendFormat("Volume name: {0}", v7_sb.s_fname).AppendLine(); xmlFSType.VolumeName = v7_sb.s_fname; sb.AppendFormat("Pack name: {0}", v7_sb.s_fpack).AppendLine(); diff --git a/DiscImageChef.Filesystems/UNIXBFS.cs b/DiscImageChef.Filesystems/UNIXBFS.cs index 6e080b635..f1daa651a 100644 --- a/DiscImageChef.Filesystems/UNIXBFS.cs +++ b/DiscImageChef.Filesystems/UNIXBFS.cs @@ -108,6 +108,8 @@ namespace DiscImageChef.Plugins xmlFSType = new Schemas.FileSystemType(); xmlFSType.Type = "BFS"; xmlFSType.VolumeName = bfs_sb.s_volume; + xmlFSType.ClusterSize = (int)imagePlugin.GetSectorSize(); + xmlFSType.Clusters = (long)(partitionEnd - partitionStart + 1); information = sb.ToString(); } diff --git a/DiscImageChef.Filesystems/ext2FS.cs b/DiscImageChef.Filesystems/ext2FS.cs index 6953dfa43..30f4ded4c 100644 --- a/DiscImageChef.Filesystems/ext2FS.cs +++ b/DiscImageChef.Filesystems/ext2FS.cs @@ -301,6 +301,7 @@ namespace DiscImageChef.Plugins { sb.AppendFormat("Volume was created on {0} for {1}", DateHandlers.UNIXUnsignedToDateTime(supblk.mkfs_t), ext_os).AppendLine(); xmlFSType.CreationDate = DateHandlers.UNIXUnsignedToDateTime(supblk.mkfs_t); + xmlFSType.CreationDateSpecified = true; } else sb.AppendFormat("Volume was created for {0}", ext_os).AppendLine(); @@ -401,6 +402,7 @@ namespace DiscImageChef.Plugins { sb.AppendFormat("Last written on {0}", DateHandlers.UNIXUnsignedToDateTime(supblk.write_t)).AppendLine(); xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(supblk.write_t); + xmlFSType.ModificationDateSpecified = true; } else sb.AppendLine("Volume has never been written"); @@ -456,6 +458,7 @@ namespace DiscImageChef.Plugins sb.AppendFormat("{0} reserved and {1} free blocks", reserved, free).AppendLine(); xmlFSType.FreeClusters = (long)free; + xmlFSType.FreeClustersSpecified = true; sb.AppendFormat("{0} inodes with {1} free inodes ({2}%)", supblk.inodes, supblk.free_inodes, supblk.free_inodes * 100 / supblk.inodes).AppendLine(); if (supblk.first_inode > 0) sb.AppendFormat("First inode is {0}", supblk.first_inode).AppendLine(); diff --git a/DiscImageChef.Filesystems/extFS.cs b/DiscImageChef.Filesystems/extFS.cs index 03dca307c..5b035b847 100644 --- a/DiscImageChef.Filesystems/extFS.cs +++ b/DiscImageChef.Filesystems/extFS.cs @@ -95,7 +95,9 @@ namespace DiscImageChef.Plugins xmlFSType = new Schemas.FileSystemType(); xmlFSType.Type = "ext"; xmlFSType.FreeClusters = ext_sb.freecountblk; + xmlFSType.FreeClustersSpecified = true; xmlFSType.ClusterSize = 1024; + xmlFSType.Clusters = (long)((partitionEnd - partitionStart + 1) * imagePlugin.GetSectorSize() / 1024); information = sb.ToString(); } diff --git a/DiscImageChef.Metadata/ChangeLog b/DiscImageChef.Metadata/ChangeLog index b26b327cc..0db1fd12f 100644 --- a/DiscImageChef.Metadata/ChangeLog +++ b/DiscImageChef.Metadata/ChangeLog @@ -1,3 +1,10 @@ +2015-12-06 Natalia Portillo + + * DiskType.cs: + * DiscImageChef.Metadata.csproj: + Added method to convert DiskType to disk type and subtype + strings. + 2015-12-05 Natalia Portillo * DiscImageChef.Metadata.csproj: diff --git a/DiscImageChef.Metadata/DiscImageChef.Metadata.csproj b/DiscImageChef.Metadata/DiscImageChef.Metadata.csproj index 0fae6cecd..93a25dfcf 100644 --- a/DiscImageChef.Metadata/DiscImageChef.Metadata.csproj +++ b/DiscImageChef.Metadata/DiscImageChef.Metadata.csproj @@ -38,6 +38,13 @@ cicm.cs + + + + {F2B84194-26EB-4227-B1C5-6602517E85AE} + DiscImageChef.CommonTypes + + \ No newline at end of file diff --git a/DiscImageChef.Metadata/DiskType.cs b/DiscImageChef.Metadata/DiskType.cs new file mode 100644 index 000000000..05b08c833 --- /dev/null +++ b/DiscImageChef.Metadata/DiskType.cs @@ -0,0 +1,352 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : DiskType.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : Component +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; + +namespace DiscImageChef.Metadata +{ + public static class DiskType + { + public static void DiskTypeToString(CommonTypes.DiskType dskType, out string DiscType, out string DiscSubType) + { + switch (dskType) + { + case CommonTypes.DiskType.BDR: + DiscType = "BD"; + DiscSubType = "BD-R"; + break; + case CommonTypes.DiskType.BDRE: + DiscType = "BD"; + DiscSubType = "BD-RE"; + break; + case CommonTypes.DiskType.BDREXL: + DiscType = "BD"; + DiscSubType = "BD-RE XL"; + break; + case CommonTypes.DiskType.BDROM: + DiscType = "BD"; + DiscSubType = "BD-ROM"; + break; + case CommonTypes.DiskType.BDRXL: + DiscType = "BD"; + DiscSubType = "BD-R XL"; + break; + case CommonTypes.DiskType.CBHD: + DiscType = "BD"; + DiscSubType = "CBHD"; + break; + case CommonTypes.DiskType.CD: + DiscType = "CD"; + DiscSubType = "CD"; + break; + case CommonTypes.DiskType.CDDA: + DiscType = "CD"; + DiscSubType = "CD Digital Audio"; + break; + case CommonTypes.DiskType.CDEG: + DiscType = "CD"; + DiscSubType = "CD+EG"; + break; + case CommonTypes.DiskType.CDG: + DiscType = "CD"; + DiscSubType = "CD+G"; + break; + case CommonTypes.DiskType.CDI: + DiscType = "CD"; + DiscSubType = "CD-i"; + break; + case CommonTypes.DiskType.CDMIDI: + DiscType = "CD"; + DiscSubType = "CD+MIDI"; + break; + case CommonTypes.DiskType.CDMO: + DiscType = "CD"; + DiscSubType = "CD-MO"; + break; + case CommonTypes.DiskType.CDMRW: + DiscType = "CD"; + DiscSubType = "CD-MRW"; + break; + case CommonTypes.DiskType.CDPLUS: + DiscType = "CD"; + DiscSubType = "CD+"; + break; + case CommonTypes.DiskType.CDR: + DiscType = "CD"; + DiscSubType = "CD-R"; + break; + case CommonTypes.DiskType.CDROM: + DiscType = "CD-ROM"; + DiscSubType = "CD"; + break; + case CommonTypes.DiskType.CDROMXA: + DiscType = "CD-ROM XA"; + DiscSubType = "CD"; + break; + case CommonTypes.DiskType.CDRW: + DiscType = "CD-RW"; + DiscSubType = "CD"; + break; + case CommonTypes.DiskType.CDV: + DiscType = "CD"; + DiscSubType = "CD-Video"; + break; + case CommonTypes.DiskType.DDCD: + DiscType = "DDCD"; + DiscSubType = "DDCD"; + break; + case CommonTypes.DiskType.DDCDR: + DiscType = "DDCD"; + DiscSubType = "DDCD-R"; + break; + case CommonTypes.DiskType.DDCDRW: + DiscType = "DDCD"; + DiscSubType = "DDCD-RW"; + break; + case CommonTypes.DiskType.DTSCD: + DiscType = "CD"; + DiscSubType = "DTS CD"; + break; + case CommonTypes.DiskType.DVDDownload: + DiscType = "DVD"; + DiscSubType = "DVD-Download"; + break; + case CommonTypes.DiskType.DVDPR: + DiscType = "DVD"; + DiscSubType = "DVD+R"; + break; + case CommonTypes.DiskType.DVDPRDL: + DiscType = "DVD"; + DiscSubType = "DVD+R DL"; + break; + case CommonTypes.DiskType.DVDPRW: + DiscType = "DVD"; + DiscSubType = "DVD+RW"; + break; + case CommonTypes.DiskType.DVDPRWDL: + DiscType = "DVD"; + DiscSubType = "DVD+RW DL"; + break; + case CommonTypes.DiskType.DVDR: + DiscType = "DVD"; + DiscSubType = "DVD-R"; + break; + case CommonTypes.DiskType.DVDRAM: + DiscType = "DVD"; + DiscSubType = "DVD-RAM"; + break; + case CommonTypes.DiskType.DVDRDL: + DiscType = "DVD"; + DiscSubType = "DVD-R DL"; + break; + case CommonTypes.DiskType.DVDROM: + DiscType = "DVD"; + DiscSubType = "DVD-ROM"; + break; + case CommonTypes.DiskType.DVDRW: + DiscType = "DVD"; + DiscSubType = "DVD-RW"; + break; + case CommonTypes.DiskType.DVDRWDL: + DiscType = "DVD"; + DiscSubType = "DVD-RW"; + break; + case CommonTypes.DiskType.EVD: + DiscType = "EVD"; + DiscSubType = "EVD"; + break; + case CommonTypes.DiskType.FDDVD: + DiscType = "FDDVD"; + DiscSubType = "FDDVD"; + break; + case CommonTypes.DiskType.FVD: + DiscType = "FVD"; + DiscSubType = "FVD"; + break; + case CommonTypes.DiskType.GDR: + DiscType = "GD"; + DiscSubType = "GD-R"; + break; + case CommonTypes.DiskType.GDROM: + DiscType = "GD"; + DiscSubType = "GD-ROM"; + break; + case CommonTypes.DiskType.GOD: + DiscType = "DVD"; + DiscSubType = "GameCube Game Disc"; + break; + case CommonTypes.DiskType.WOD: + DiscType = "DVD"; + DiscSubType = "Wii Optical Disc"; + break; + case CommonTypes.DiskType.WUOD: + DiscType = "BD"; + DiscSubType = "Wii U Optical Disc"; + break; + case CommonTypes.DiskType.HDDVDR: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-R"; + break; + case CommonTypes.DiskType.HDDVDRAM: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-RAM"; + break; + case CommonTypes.DiskType.HDDVDRDL: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-R DL"; + break; + case CommonTypes.DiskType.HDDVDROM: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-ROM"; + break; + case CommonTypes.DiskType.HDDVDRW: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-RW"; + break; + case CommonTypes.DiskType.HDDVDRWDL: + DiscType = "HD DVD"; + DiscSubType = "HD DVD-RW DL"; + break; + case CommonTypes.DiskType.HDVMD: + DiscType = "HD VMD"; + DiscSubType = "HD VMD"; + break; + case CommonTypes.DiskType.HiMD: + DiscType = "MiniDisc"; + DiscSubType = "HiMD"; + break; + case CommonTypes.DiskType.HVD: + DiscType = "HVD"; + DiscSubType = "HVD"; + break; + case CommonTypes.DiskType.LD: + DiscType = "LaserDisc"; + DiscSubType = "LaserDisc"; + break; + case CommonTypes.DiskType.LDROM: + DiscType = "LaserDisc"; + DiscSubType = "LD-ROM"; + break; + case CommonTypes.DiskType.MD: + DiscType = "MiniDisc"; + DiscSubType = "MiniDisc"; + break; + case CommonTypes.DiskType.MEGACD: + DiscType = "CD"; + DiscSubType = "Sega Mega CD"; + break; + case CommonTypes.DiskType.PCD: + DiscType = "CD"; + DiscSubType = "Photo CD"; + break; + case CommonTypes.DiskType.PS1CD: + DiscType = "CD"; + DiscSubType = "PlayStation Game Disc"; + break; + case CommonTypes.DiskType.PS2CD: + DiscType = "CD"; + DiscSubType = "PlayStation 2 Game Disc"; + break; + case CommonTypes.DiskType.PS2DVD: + DiscType = "DVD"; + DiscSubType = "PlayStation 2 Game Disc"; + break; + case CommonTypes.DiskType.PS3BD: + DiscType = "BD"; + DiscSubType = "PlayStation 3 Game Disc"; + break; + case CommonTypes.DiskType.PS3DVD: + DiscType = "DVD"; + DiscSubType = "PlayStation 3 Game Disc"; + break; + case CommonTypes.DiskType.PS4BD: + DiscType = "BD"; + DiscSubType = "PlayStation 4 Game Disc"; + break; + case CommonTypes.DiskType.SACD: + DiscType = "SACD"; + DiscSubType = "Super Audio CD"; + break; + case CommonTypes.DiskType.SATURNCD: + DiscType = "CD"; + DiscSubType = "Sega Saturn CD"; + break; + case CommonTypes.DiskType.SVCD: + DiscType = "CD"; + DiscSubType = "Super Video CD"; + break; + case CommonTypes.DiskType.SVOD: + DiscType = "SVOD"; + DiscSubType = "SVOD"; + break; + case CommonTypes.DiskType.UDO: + DiscType = "UDO"; + DiscSubType = "UDO"; + break; + case CommonTypes.DiskType.UMD: + DiscType = "UMD"; + DiscSubType = "Universal Media Disc"; + break; + case CommonTypes.DiskType.VCD: + DiscType = "CD"; + DiscSubType = "Video CD"; + break; + case CommonTypes.DiskType.XGD: + DiscType = "DVD"; + DiscSubType = "Xbox Game Disc (XGD)"; + break; + case CommonTypes.DiskType.XGD2: + DiscType = "DVD"; + DiscSubType = "Xbox 360 Game Disc (XGD2)"; + break; + case CommonTypes.DiskType.XGD3: + DiscType = "DVD"; + DiscSubType = "Xbox 360 Game Disc (XGD3)"; + break; + case CommonTypes.DiskType.XGD4: + DiscType = "BD"; + DiscSubType = "Xbox One Game Disc (XGD4)"; + break; + default: + DiscType = "Unknown"; + DiscSubType = "Unknown"; + break; + } + } + } +} + diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index e128b5625..4cd41a04e 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,15 @@ +2015-12-06 Natalia Portillo + + * Commands/Checksum.cs: + Checking memory usage on each step makes checksum + calculation abismally slower. Removed. + + * Main.cs: + * Options.cs: + * DiscImageChef.csproj: + * Commands/CreateSidecar.cs: + Added method for creating CICM Metadata XML sidecar. + 2015-12-04 Natalia Portillo * Commands/MediaInfo.cs: diff --git a/DiscImageChef/Commands/Checksum.cs b/DiscImageChef/Commands/Checksum.cs index 697fd0416..db2f78cda 100644 --- a/DiscImageChef/Commands/Checksum.cs +++ b/DiscImageChef/Commands/Checksum.cs @@ -77,8 +77,6 @@ namespace DiscImageChef.Commands } inputFormat.OpenImage(options.InputFile); - long maxMemory = GC.GetTotalMemory(false); - long snapMemory; if (inputFormat.ImageInfo.imageHasPartitions) { @@ -303,10 +301,6 @@ namespace DiscImageChef.Commands spamsumThread.Start(spamsumPkt); } - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; - while (adlerThread.IsAlive || crc16Thread.IsAlive || crc32Thread.IsAlive || crc64Thread.IsAlive || //fletcher16Thread.IsAlive || fletcher32Thread.IsAlive || @@ -330,10 +324,6 @@ namespace DiscImageChef.Commands sha384Thread = new Thread(updateSHA384); sha512Thread = new Thread(updateSHA512); spamsumThread = new Thread(updateSpamSum); - - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; } } @@ -511,10 +501,6 @@ namespace DiscImageChef.Commands spamsumThread.Start(spamsumPkt); } - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; - while (adlerThread.IsAlive || crc16Thread.IsAlive || crc32Thread.IsAlive || crc64Thread.IsAlive || //fletcher16Thread.IsAlive || fletcher32Thread.IsAlive || @@ -538,10 +524,6 @@ namespace DiscImageChef.Commands sha384Thread = new Thread(updateSHA384); sha512Thread = new Thread(updateSHA512); spamsumThread = new Thread(updateSpamSum); - - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; } if (options.SeparatedTracks) @@ -612,10 +594,6 @@ namespace DiscImageChef.Commands spamsumThread.Start(spamsumPktTrack); } - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; - while (adlerThread.IsAlive || crc16Thread.IsAlive || crc32Thread.IsAlive || crc64Thread.IsAlive || //fletcher16Thread.IsAlive || fletcher32Thread.IsAlive || @@ -639,10 +617,6 @@ namespace DiscImageChef.Commands sha384Thread = new Thread(updateSHA384); sha512Thread = new Thread(updateSHA512); spamsumThread = new Thread(updateSpamSum); - - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; } } @@ -756,10 +730,6 @@ namespace DiscImageChef.Commands spamsumThread.Start(spamsumPkt); } - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; - while (adlerThread.IsAlive || crc16Thread.IsAlive || crc32Thread.IsAlive || crc64Thread.IsAlive || //fletcher16Thread.IsAlive || fletcher32Thread.IsAlive || @@ -783,10 +753,6 @@ namespace DiscImageChef.Commands sha384Thread = new Thread(updateSHA384); sha512Thread = new Thread(updateSHA512); spamsumThread = new Thread(updateSpamSum); - - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; } } @@ -1025,10 +991,6 @@ namespace DiscImageChef.Commands spamsumThread.Start(spamsumPkt); } - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; - while (adlerThread.IsAlive || crc16Thread.IsAlive || crc32Thread.IsAlive || crc64Thread.IsAlive || //fletcher16Thread.IsAlive || fletcher32Thread.IsAlive || @@ -1052,10 +1014,6 @@ namespace DiscImageChef.Commands sha384Thread = new Thread(updateSHA384); sha512Thread = new Thread(updateSHA512); spamsumThread = new Thread(updateSpamSum); - - snapMemory = GC.GetTotalMemory(false); - if (snapMemory > maxMemory) - maxMemory = snapMemory; } DicConsole.WriteLine(); @@ -1087,8 +1045,6 @@ namespace DiscImageChef.Commands if (options.DoSpamSum) DicConsole.WriteLine("Disk's SpamSum: {0}", ssctx.End()); } - - DicConsole.DebugWriteLine("Checksum command", "Maximum memory used has been {0} bytes", maxMemory); } #region Threading helpers diff --git a/DiscImageChef/Commands/CreateSidecar.cs b/DiscImageChef/Commands/CreateSidecar.cs index cd48cbdb4..3967ea45b 100644 --- a/DiscImageChef/Commands/CreateSidecar.cs +++ b/DiscImageChef/Commands/CreateSidecar.cs @@ -36,14 +36,1456 @@ // ****************************************************************************/ // //$Id$ using System; +using Schemas; +using System.Collections.Generic; +using DiscImageChef.Plugins; +using DiscImageChef.ImagePlugins; +using DiscImageChef.Console; +using DiscImageChef.Checksums; +using System.IO; +using System.Threading; +using DiscImageChef.CommonTypes; +using DiscImageChef.PartPlugins; namespace DiscImageChef.Commands { - public class CreateSidecar + public static class CreateSidecar { - public CreateSidecar() + public static void doSidecar(CreateSidecarSubOptions options) { + CICMMetadataType sidecar = new CICMMetadataType(); + PluginBase plugins = new PluginBase(); + plugins.RegisterAllPlugins(); + ImagePlugin _imageFormat; + + try + { + _imageFormat = ImageFormat.Detect(options.InputFile); + + if (_imageFormat == null) + { + DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); + return; + } + else + { + if (options.Verbose) + DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", _imageFormat.Name, _imageFormat.PluginUUID); + else + DicConsole.WriteLine("Image format identified by {0}.", _imageFormat.Name); + } + + try + { + if (!_imageFormat.OpenImage(options.InputFile)) + { + DicConsole.WriteLine("Unable to open image format"); + DicConsole.WriteLine("No error given"); + return; + } + + DicConsole.DebugWriteLine("Analyze command", "Correctly opened image file."); + } + catch (Exception ex) + { + System.Console.Error.WriteLine("Unable to open image format"); + DicConsole.ErrorWriteLine("Error: {0}", ex.Message); + return; + } + + FileInfo fi = new FileInfo(options.InputFile); + FileStream fs = new FileStream(options.InputFile, FileMode.Open, FileAccess.Read); + + Adler32Context adler32ctx = new Adler32Context(); + CRC16Context crc16ctx = new CRC16Context(); + CRC32Context crc32ctx = new CRC32Context(); + CRC64Context crc64ctx = new CRC64Context(); + MD5Context md5ctx = new MD5Context(); + RIPEMD160Context ripemd160ctx = new RIPEMD160Context(); + SHA1Context sha1ctx = new SHA1Context(); + SHA256Context sha256ctx = new SHA256Context(); + SHA384Context sha384ctx = new SHA384Context(); + SHA512Context sha512ctx = new SHA512Context(); + SpamSumContext ssctx = new SpamSumContext(); + + Thread adlerThread = new Thread(updateAdler); + Thread crc16Thread = new Thread(updateCRC16); + Thread crc32Thread = new Thread(updateCRC32); + Thread crc64Thread = new Thread(updateCRC64); + Thread md5Thread = new Thread(updateMD5); + Thread ripemd160Thread = new Thread(updateRIPEMD160); + Thread sha1Thread = new Thread(updateSHA1); + Thread sha256Thread = new Thread(updateSHA256); + Thread sha384Thread = new Thread(updateSHA384); + Thread sha512Thread = new Thread(updateSHA512); + Thread spamsumThread = new Thread(updateSpamSum); + + adlerPacket adlerPkt = new adlerPacket(); + crc16Packet crc16Pkt = new crc16Packet(); + crc32Packet crc32Pkt = new crc32Packet(); + crc64Packet crc64Pkt = new crc64Packet(); + md5Packet md5Pkt = new md5Packet(); + ripemd160Packet ripemd160Pkt = new ripemd160Packet(); + sha1Packet sha1Pkt = new sha1Packet(); + sha256Packet sha256Pkt = new sha256Packet(); + sha384Packet sha384Pkt = new sha384Packet(); + sha512Packet sha512Pkt = new sha512Packet(); + spamsumPacket spamsumPkt = new spamsumPacket(); + + adler32ctx.Init(); + adlerPkt.context = adler32ctx; + crc16ctx.Init(); + crc16Pkt.context = crc16ctx; + crc32ctx.Init(); + crc32Pkt.context = crc32ctx; + crc64ctx.Init(); + crc64Pkt.context = crc64ctx; + md5ctx.Init(); + md5Pkt.context = md5ctx; + ripemd160ctx.Init(); + ripemd160Pkt.context = ripemd160ctx; + sha1ctx.Init(); + sha1Pkt.context = sha1ctx; + sha256ctx.Init(); + sha256Pkt.context = sha256ctx; + sha384ctx.Init(); + sha384Pkt.context = sha384ctx; + sha512ctx.Init(); + sha512Pkt.context = sha512ctx; + ssctx.Init(); + spamsumPkt.context = ssctx; + + byte[] data; + long position = 0; + while (position < (fi.Length - 1048576)) + { + data = new byte[1048576]; + fs.Read(data, 0, 1048576); + + DicConsole.Write("\rHashing image file byte {0} of {1}", position, fi.Length); + + adlerPkt.data = data; + adlerThread.Start(adlerPkt); + crc16Pkt.data = data; + crc16Thread.Start(crc16Pkt); + crc32Pkt.data = data; + crc32Thread.Start(crc32Pkt); + crc64Pkt.data = data; + crc64Thread.Start(crc64Pkt); + md5Pkt.data = data; + md5Thread.Start(md5Pkt); + ripemd160Pkt.data = data; + ripemd160Thread.Start(ripemd160Pkt); + sha1Pkt.data = data; + sha1Thread.Start(sha1Pkt); + sha256Pkt.data = data; + sha256Thread.Start(sha256Pkt); + sha384Pkt.data = data; + sha384Thread.Start(sha384Pkt); + sha512Pkt.data = data; + sha512Thread.Start(sha512Pkt); + spamsumPkt.data = data; + spamsumThread.Start(spamsumPkt); + + while (adlerThread.IsAlive || crc16Thread.IsAlive || + crc32Thread.IsAlive || crc64Thread.IsAlive || + md5Thread.IsAlive || ripemd160Thread.IsAlive || + sha1Thread.IsAlive || sha256Thread.IsAlive || + sha384Thread.IsAlive || sha512Thread.IsAlive || + spamsumThread.IsAlive) + { + } + + adlerThread = new Thread(updateAdler); + crc16Thread = new Thread(updateCRC16); + crc32Thread = new Thread(updateCRC32); + crc64Thread = new Thread(updateCRC64); + md5Thread = new Thread(updateMD5); + ripemd160Thread = new Thread(updateRIPEMD160); + sha1Thread = new Thread(updateSHA1); + sha256Thread = new Thread(updateSHA256); + sha384Thread = new Thread(updateSHA384); + sha512Thread = new Thread(updateSHA512); + spamsumThread = new Thread(updateSpamSum); + + position += 1048576; + } + + data = new byte[fi.Length - position]; + fs.Read(data, 0, (int)(fi.Length - position)); + + DicConsole.Write("\rHashing image file byte {0} of {1}", position, fi.Length); + + adlerPkt.data = data; + adlerThread.Start(adlerPkt); + crc16Pkt.data = data; + crc16Thread.Start(crc16Pkt); + crc32Pkt.data = data; + crc32Thread.Start(crc32Pkt); + crc64Pkt.data = data; + crc64Thread.Start(crc64Pkt); + md5Pkt.data = data; + md5Thread.Start(md5Pkt); + ripemd160Pkt.data = data; + ripemd160Thread.Start(ripemd160Pkt); + sha1Pkt.data = data; + sha1Thread.Start(sha1Pkt); + sha256Pkt.data = data; + sha256Thread.Start(sha256Pkt); + sha384Pkt.data = data; + sha384Thread.Start(sha384Pkt); + sha512Pkt.data = data; + sha512Thread.Start(sha512Pkt); + spamsumPkt.data = data; + spamsumThread.Start(spamsumPkt); + + while (adlerThread.IsAlive || crc16Thread.IsAlive || + crc32Thread.IsAlive || crc64Thread.IsAlive || + md5Thread.IsAlive || ripemd160Thread.IsAlive || + sha1Thread.IsAlive || sha256Thread.IsAlive || + sha384Thread.IsAlive || sha512Thread.IsAlive || + spamsumThread.IsAlive) + { + } + + DicConsole.WriteLine(); + fs.Close(); + + List imgChecksums = new List(); + + ChecksumType chk = new ChecksumType(); + chk.type = ChecksumTypeType.adler32; + chk.Value = adler32ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc16; + chk.Value = crc16ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc32; + chk.Value = crc32ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc64; + chk.Value = crc64ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.md5; + chk.Value = md5ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.ripemd160; + chk.Value = ripemd160ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha1; + chk.Value = sha1ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha256; + chk.Value = sha256ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha384; + chk.Value = sha384ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha512; + chk.Value = sha512ctx.End(); + imgChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.spamsum; + chk.Value = ssctx.End(); + imgChecksums.Add(chk); + + switch (_imageFormat.ImageInfo.xmlMediaType) + { + case XmlMediaType.OpticalDisc: + { + sidecar.OpticalDisc = new OpticalDiscType[1]; + sidecar.OpticalDisc[0] = new OpticalDiscType(); + sidecar.OpticalDisc[0].Checksums = imgChecksums.ToArray(); + sidecar.OpticalDisc[0].Image = new ImageType(); + sidecar.OpticalDisc[0].Image.format = _imageFormat.GetImageFormat(); + sidecar.OpticalDisc[0].Image.offset = 0; + sidecar.OpticalDisc[0].Image.offsetSpecified = true; + sidecar.OpticalDisc[0].Image.Value = Path.GetFileName(options.InputFile); + sidecar.OpticalDisc[0].Size = fi.Length; + sidecar.OpticalDisc[0].Sequence = new SequenceType(); + if (_imageFormat.GetDiskSequence() != 0 && _imageFormat.GetLastDiskSequence() != 0) + { + sidecar.OpticalDisc[0].Sequence.MediaSequence = _imageFormat.GetDiskSequence(); + sidecar.OpticalDisc[0].Sequence.TotalMedia = _imageFormat.GetDiskSequence(); + } + else + { + sidecar.OpticalDisc[0].Sequence.MediaSequence = 1; + sidecar.OpticalDisc[0].Sequence.TotalMedia = 1; + } + sidecar.OpticalDisc[0].Sequence.MediaTitle = _imageFormat.GetImageName(); + + DiskType dskType = _imageFormat.ImageInfo.diskType; + + foreach (DiskTagType tagType in _imageFormat.ImageInfo.readableDiskTags) + { + switch (tagType) + { + case DiskTagType.CD_ATIP: + sidecar.OpticalDisc[0].ATIP = new DumpType(); + sidecar.OpticalDisc[0].ATIP.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.CD_ATIP)).ToArray(); + sidecar.OpticalDisc[0].ATIP.Size = _imageFormat.ReadDiskTag(DiskTagType.CD_ATIP).Length; + Decoders.CD.ATIP.CDATIP? atip = Decoders.CD.ATIP.Decode(_imageFormat.ReadDiskTag(DiskTagType.CD_ATIP)); + if (atip.HasValue) + { + if (atip.Value.DDCD) + dskType = atip.Value.DiscType ? DiskType.DDCDRW : DiskType.DDCDR; + else + dskType = atip.Value.DiscType ? DiskType.CDRW : DiskType.CDR; + } + break; + case DiskTagType.DVD_BCA: + sidecar.OpticalDisc[0].BCA = new DumpType(); + sidecar.OpticalDisc[0].BCA.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.DVD_BCA)).ToArray(); + sidecar.OpticalDisc[0].BCA.Size = _imageFormat.ReadDiskTag(DiskTagType.DVD_BCA).Length; + break; + case DiskTagType.BD_BCA: + sidecar.OpticalDisc[0].BCA = new DumpType(); + sidecar.OpticalDisc[0].BCA.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.BD_BCA)).ToArray(); + sidecar.OpticalDisc[0].BCA.Size = _imageFormat.ReadDiskTag(DiskTagType.BD_BCA).Length; + break; + case DiskTagType.DVD_CMI: + sidecar.OpticalDisc[0].CMI = new DumpType(); + Decoders.DVD.CSS_CPRM.LeadInCopyright? cmi = Decoders.DVD.CSS_CPRM.DecodeLeadInCopyright(_imageFormat.ReadDiskTag(DiskTagType.DVD_CMI)); + if (cmi.HasValue) + { + switch (cmi.Value.CopyrightType) + { + case Decoders.DVD.CopyrightType.AACS: + sidecar.OpticalDisc[0].CopyProtection = "AACS"; + break; + case Decoders.DVD.CopyrightType.CSS: + sidecar.OpticalDisc[0].CopyProtection = "CSS"; + break; + case Decoders.DVD.CopyrightType.CPRM: + sidecar.OpticalDisc[0].CopyProtection = "CPRM"; + break; + } + } + sidecar.OpticalDisc[0].CMI.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.DVD_CMI)).ToArray(); + sidecar.OpticalDisc[0].CMI.Size = _imageFormat.ReadDiskTag(DiskTagType.DVD_CMI).Length; + break; + case DiskTagType.DVD_DMI: + sidecar.OpticalDisc[0].DMI = new DumpType(); + sidecar.OpticalDisc[0].DMI.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.DVD_DMI)).ToArray(); + sidecar.OpticalDisc[0].DMI.Size = _imageFormat.ReadDiskTag(DiskTagType.DVD_DMI).Length; + if (Decoders.Xbox.DMI.IsXbox(_imageFormat.ReadDiskTag(DiskTagType.DVD_DMI))) + { + dskType = DiskType.XGD; + sidecar.OpticalDisc[0].Dimensions = new DimensionsType(); + sidecar.OpticalDisc[0].Dimensions.Diameter = 120; + } + else if (Decoders.Xbox.DMI.IsXbox360(_imageFormat.ReadDiskTag(DiskTagType.DVD_DMI))) + { + dskType = DiskType.XGD2; + sidecar.OpticalDisc[0].Dimensions = new DimensionsType(); + sidecar.OpticalDisc[0].Dimensions.Diameter = 120; + } + break; + case DiskTagType.DVD_PFI: + sidecar.OpticalDisc[0].PFI = new DumpType(); + sidecar.OpticalDisc[0].PFI.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.DVD_PFI)).ToArray(); + sidecar.OpticalDisc[0].PFI.Size = _imageFormat.ReadDiskTag(DiskTagType.DVD_PFI).Length; + Decoders.DVD.PFI.PhysicalFormatInformation? pfi = Decoders.DVD.PFI.Decode(_imageFormat.ReadDiskTag(DiskTagType.DVD_PFI)); + if (pfi.HasValue) + { + if (dskType != DiskType.XGD && + dskType != DiskType.XGD2 && + dskType != DiskType.XGD3) + { + switch (pfi.Value.DiskCategory) + { + case Decoders.DVD.DiskCategory.DVDPR: + dskType = DiskType.DVDPR; + break; + case Decoders.DVD.DiskCategory.DVDPRDL: + dskType = DiskType.DVDPRDL; + break; + case Decoders.DVD.DiskCategory.DVDPRW: + dskType = DiskType.DVDPRW; + break; + case Decoders.DVD.DiskCategory.DVDPRWDL: + dskType = DiskType.DVDPRWDL; + break; + case Decoders.DVD.DiskCategory.DVDR: + dskType = DiskType.DVDR; + break; + case Decoders.DVD.DiskCategory.DVDRAM: + dskType = DiskType.DVDRAM; + break; + case Decoders.DVD.DiskCategory.DVDROM: + dskType = DiskType.DVDROM; + break; + case Decoders.DVD.DiskCategory.DVDRW: + dskType = DiskType.DVDRW; + break; + case Decoders.DVD.DiskCategory.HDDVDR: + dskType = DiskType.HDDVDR; + break; + case Decoders.DVD.DiskCategory.HDDVDRAM: + dskType = DiskType.HDDVDRAM; + break; + case Decoders.DVD.DiskCategory.HDDVDROM: + dskType = DiskType.HDDVDROM; + break; + case Decoders.DVD.DiskCategory.HDDVDRW: + dskType = DiskType.HDDVDRW; + break; + case Decoders.DVD.DiskCategory.Nintendo: + dskType = DiskType.GOD; + break; + case Decoders.DVD.DiskCategory.UMD: + dskType = DiskType.UMD; + break; + } + + if (dskType == DiskType.DVDR && pfi.Value.PartVersion == 6) + dskType = DiskType.DVDRDL; + if (dskType == DiskType.DVDRW && pfi.Value.PartVersion == 3) + dskType = DiskType.DVDRWDL; + if (dskType == DiskType.GOD && pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.OneTwenty) + dskType = DiskType.WOD; + + sidecar.OpticalDisc[0].Dimensions = new DimensionsType(); + if (dskType == DiskType.UMD) + sidecar.OpticalDisc[0].Dimensions.Diameter = 60; + else if (pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.Eighty) + sidecar.OpticalDisc[0].Dimensions.Diameter = 80; + else if (pfi.Value.DiscSize == DiscImageChef.Decoders.DVD.DVDSize.OneTwenty) + sidecar.OpticalDisc[0].Dimensions.Diameter = 120; + } + } + break; + case DiskTagType.CD_PMA: + sidecar.OpticalDisc[0].PMA = new DumpType(); + sidecar.OpticalDisc[0].PMA.Checksums = GetChecksums(_imageFormat.ReadDiskTag(DiskTagType.CD_PMA)).ToArray(); + sidecar.OpticalDisc[0].PMA.Size = _imageFormat.ReadDiskTag(DiskTagType.CD_PMA).Length; + break; + } + } + + string dscType, dscSubType; + Metadata.DiskType.DiskTypeToString(dskType, out dscType, out dscSubType); + sidecar.OpticalDisc[0].DiscType = dscType; + sidecar.OpticalDisc[0].DiscSubType = dscSubType; + + try + { + List sessions = _imageFormat.GetSessions(); + sidecar.OpticalDisc[0].Sessions = sessions != null ? sessions.Count : 1; + } + catch + { + sidecar.OpticalDisc[0].Sessions = 1; + } + + List tracks = _imageFormat.GetTracks(); + List trksLst = null; + if (tracks != null) + { + sidecar.OpticalDisc[0].Tracks = new int[1]; + sidecar.OpticalDisc[0].Tracks[0] = tracks.Count; + trksLst = new List(); + } + + foreach (Track trk in tracks) + { + Schemas.TrackType xmlTrk = new Schemas.TrackType(); + switch (trk.TrackType) + { + case DiscImageChef.ImagePlugins.TrackType.Audio: + xmlTrk.TrackType1 = TrackTypeTrackType.audio; + break; + case DiscImageChef.ImagePlugins.TrackType.CDMode2Form2: + xmlTrk.TrackType1 = TrackTypeTrackType.m2f2; + break; + case DiscImageChef.ImagePlugins.TrackType.CDMode2Formless: + xmlTrk.TrackType1 = TrackTypeTrackType.mode2; + break; + case DiscImageChef.ImagePlugins.TrackType.CDMode2Form1: + xmlTrk.TrackType1 = TrackTypeTrackType.m2f1; + break; + case DiscImageChef.ImagePlugins.TrackType.CDMode1: + xmlTrk.TrackType1 = TrackTypeTrackType.mode1; + break; + case DiscImageChef.ImagePlugins.TrackType.Data: + switch (sidecar.OpticalDisc[0].DiscType) + { + case "BD": + xmlTrk.TrackType1 = TrackTypeTrackType.bluray; + break; + case "DDCD": + xmlTrk.TrackType1 = TrackTypeTrackType.ddcd; + break; + case "DVD": + xmlTrk.TrackType1 = TrackTypeTrackType.dvd; + break; + case "HD DVD": + xmlTrk.TrackType1 = TrackTypeTrackType.hddvd; + break; + default: + xmlTrk.TrackType1 = TrackTypeTrackType.mode1; + break; + } + break; + } + xmlTrk.Sequence = new TrackSequenceType(); + xmlTrk.Sequence.Session = trk.TrackSession; + xmlTrk.Sequence.TrackNumber = (int)trk.TrackSequence; + xmlTrk.StartSector = (long)trk.TrackStartSector; + xmlTrk.EndSector = (long)trk.TrackEndSector; + + if (sidecar.OpticalDisc[0].DiscType == "CD" || + sidecar.OpticalDisc[0].DiscType == "GD") + { + xmlTrk.StartMSF = LbaToMsf(xmlTrk.StartSector); + xmlTrk.EndMSF = LbaToMsf(xmlTrk.EndSector); + } + else if (sidecar.OpticalDisc[0].DiscType == "DDCD") + { + xmlTrk.StartMSF = DdcdLbaToMsf(xmlTrk.StartSector); + xmlTrk.EndMSF = DdcdLbaToMsf(xmlTrk.EndSector); + } + + xmlTrk.Image = new ImageType(); + xmlTrk.Image.Value = Path.GetFileName(trk.TrackFile); + if (trk.TrackFileOffset > 0) + { + xmlTrk.Image.offset = (long)trk.TrackFileOffset; + xmlTrk.Image.offsetSpecified = true; + } + + xmlTrk.Image.format = trk.TrackFileType; + xmlTrk.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * trk.TrackRawBytesPerSector; + xmlTrk.BytesPerSector = trk.TrackBytesPerSector; + + uint sectorsToRead = 512; + + adler32ctx = new Adler32Context(); + crc16ctx = new CRC16Context(); + crc32ctx = new CRC32Context(); + crc64ctx = new CRC64Context(); + md5ctx = new MD5Context(); + ripemd160ctx = new RIPEMD160Context(); + sha1ctx = new SHA1Context(); + sha256ctx = new SHA256Context(); + sha384ctx = new SHA384Context(); + sha512ctx = new SHA512Context(); + ssctx = new SpamSumContext(); + + adlerThread = new Thread(updateAdler); + crc16Thread = new Thread(updateCRC16); + crc32Thread = new Thread(updateCRC32); + crc64Thread = new Thread(updateCRC64); + md5Thread = new Thread(updateMD5); + ripemd160Thread = new Thread(updateRIPEMD160); + sha1Thread = new Thread(updateSHA1); + sha256Thread = new Thread(updateSHA256); + sha384Thread = new Thread(updateSHA384); + sha512Thread = new Thread(updateSHA512); + spamsumThread = new Thread(updateSpamSum); + + adlerPkt = new adlerPacket(); + crc16Pkt = new crc16Packet(); + crc32Pkt = new crc32Packet(); + crc64Pkt = new crc64Packet(); + md5Pkt = new md5Packet(); + ripemd160Pkt = new ripemd160Packet(); + sha1Pkt = new sha1Packet(); + sha256Pkt = new sha256Packet(); + sha384Pkt = new sha384Packet(); + sha512Pkt = new sha512Packet(); + spamsumPkt = new spamsumPacket(); + + adler32ctx.Init(); + adlerPkt.context = adler32ctx; + crc16ctx.Init(); + crc16Pkt.context = crc16ctx; + crc32ctx.Init(); + crc32Pkt.context = crc32ctx; + crc64ctx.Init(); + crc64Pkt.context = crc64ctx; + md5ctx.Init(); + md5Pkt.context = md5ctx; + ripemd160ctx.Init(); + ripemd160Pkt.context = ripemd160ctx; + sha1ctx.Init(); + sha1Pkt.context = sha1ctx; + sha256ctx.Init(); + sha256Pkt.context = sha256ctx; + sha384ctx.Init(); + sha384Pkt.context = sha384ctx; + sha512ctx.Init(); + sha512Pkt.context = sha512ctx; + ssctx.Init(); + spamsumPkt.context = ssctx; + + ulong sectors = (ulong)(xmlTrk.EndSector - xmlTrk.StartSector + 1); + ulong doneSectors = 0; + + while (doneSectors < sectors) + { + byte[] sector; + + if ((sectors - doneSectors) >= sectorsToRead) + { + sector = _imageFormat.ReadSectorsLong(doneSectors, sectorsToRead, (uint)xmlTrk.Sequence.TrackNumber); + DicConsole.Write("\rHashings sectors {0} to {2} of track {1} ({3} sectors)", doneSectors, xmlTrk.Sequence.TrackNumber, doneSectors + sectorsToRead, sectors); + doneSectors += sectorsToRead; + } + else + { + sector = _imageFormat.ReadSectorsLong(doneSectors, (uint)(sectors - doneSectors), (uint)xmlTrk.Sequence.TrackNumber); + DicConsole.Write("\rHashings sectors {0} to {2} of track {1} ({3} sectors)", doneSectors, xmlTrk.Sequence.TrackNumber, doneSectors + (sectors - doneSectors), sectors); + doneSectors += (sectors - doneSectors); + } + + adlerPkt.data = sector; + adlerThread.Start(adlerPkt); + crc16Pkt.data = sector; + crc16Thread.Start(crc16Pkt); + crc32Pkt.data = sector; + crc32Thread.Start(crc32Pkt); + crc64Pkt.data = sector; + crc64Thread.Start(crc64Pkt); + md5Pkt.data = sector; + md5Thread.Start(md5Pkt); + ripemd160Pkt.data = sector; + ripemd160Thread.Start(ripemd160Pkt); + sha1Pkt.data = sector; + sha1Thread.Start(sha1Pkt); + sha256Pkt.data = sector; + sha256Thread.Start(sha256Pkt); + sha384Pkt.data = sector; + sha384Thread.Start(sha384Pkt); + sha512Pkt.data = sector; + sha512Thread.Start(sha512Pkt); + spamsumPkt.data = sector; + spamsumThread.Start(spamsumPkt); + + while (adlerThread.IsAlive || crc16Thread.IsAlive || + crc32Thread.IsAlive || crc64Thread.IsAlive || + md5Thread.IsAlive || ripemd160Thread.IsAlive || + sha1Thread.IsAlive || sha256Thread.IsAlive || + sha384Thread.IsAlive || sha512Thread.IsAlive || + spamsumThread.IsAlive) + { + } + + adlerThread = new Thread(updateAdler); + crc16Thread = new Thread(updateCRC16); + crc32Thread = new Thread(updateCRC32); + crc64Thread = new Thread(updateCRC64); + md5Thread = new Thread(updateMD5); + ripemd160Thread = new Thread(updateRIPEMD160); + sha1Thread = new Thread(updateSHA1); + sha256Thread = new Thread(updateSHA256); + sha384Thread = new Thread(updateSHA384); + sha512Thread = new Thread(updateSHA512); + spamsumThread = new Thread(updateSpamSum); + } + + List trkChecksums = new List(); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.adler32; + chk.Value = adler32ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc16; + chk.Value = crc16ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc32; + chk.Value = crc32ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc64; + chk.Value = crc64ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.md5; + chk.Value = md5ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.ripemd160; + chk.Value = ripemd160ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha1; + chk.Value = sha1ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha256; + chk.Value = sha256ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha384; + chk.Value = sha384ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha512; + chk.Value = sha512ctx.End(); + trkChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.spamsum; + chk.Value = ssctx.End(); + trkChecksums.Add(chk); + + xmlTrk.Checksums = trkChecksums.ToArray(); + + DicConsole.WriteLine(); + + if (trk.TrackSubchannelType != TrackSubchannelType.None) + { + xmlTrk.SubChannel = new SubChannelType(); + xmlTrk.SubChannel.Image = new ImageType(); + switch (trk.TrackSubchannelType) + { + case TrackSubchannelType.Packed: + case TrackSubchannelType.PackedInterleaved: + xmlTrk.SubChannel.Image.format = "rw"; + break; + case TrackSubchannelType.Raw: + case TrackSubchannelType.RawInterleaved: + xmlTrk.SubChannel.Image.format = "rw_raw"; + break; + } + + if (trk.TrackFileOffset > 0) + { + xmlTrk.SubChannel.Image.offset = (long)trk.TrackSubchannelOffset; + xmlTrk.SubChannel.Image.offsetSpecified = true; + } + xmlTrk.SubChannel.Image.Value = trk.TrackSubchannelFile; + + // TODO: Packed subchannel has different size? + xmlTrk.SubChannel.Size = (xmlTrk.EndSector - xmlTrk.StartSector + 1) * 96; + + adler32ctx = new Adler32Context(); + crc16ctx = new CRC16Context(); + crc32ctx = new CRC32Context(); + crc64ctx = new CRC64Context(); + md5ctx = new MD5Context(); + ripemd160ctx = new RIPEMD160Context(); + sha1ctx = new SHA1Context(); + sha256ctx = new SHA256Context(); + sha384ctx = new SHA384Context(); + sha512ctx = new SHA512Context(); + ssctx = new SpamSumContext(); + + adlerThread = new Thread(updateAdler); + crc16Thread = new Thread(updateCRC16); + crc32Thread = new Thread(updateCRC32); + crc64Thread = new Thread(updateCRC64); + md5Thread = new Thread(updateMD5); + ripemd160Thread = new Thread(updateRIPEMD160); + sha1Thread = new Thread(updateSHA1); + sha256Thread = new Thread(updateSHA256); + sha384Thread = new Thread(updateSHA384); + sha512Thread = new Thread(updateSHA512); + spamsumThread = new Thread(updateSpamSum); + + adlerPkt = new adlerPacket(); + crc16Pkt = new crc16Packet(); + crc32Pkt = new crc32Packet(); + crc64Pkt = new crc64Packet(); + md5Pkt = new md5Packet(); + ripemd160Pkt = new ripemd160Packet(); + sha1Pkt = new sha1Packet(); + sha256Pkt = new sha256Packet(); + sha384Pkt = new sha384Packet(); + sha512Pkt = new sha512Packet(); + spamsumPkt = new spamsumPacket(); + + adler32ctx.Init(); + adlerPkt.context = adler32ctx; + crc16ctx.Init(); + crc16Pkt.context = crc16ctx; + crc32ctx.Init(); + crc32Pkt.context = crc32ctx; + crc64ctx.Init(); + crc64Pkt.context = crc64ctx; + md5ctx.Init(); + md5Pkt.context = md5ctx; + ripemd160ctx.Init(); + ripemd160Pkt.context = ripemd160ctx; + sha1ctx.Init(); + sha1Pkt.context = sha1ctx; + sha256ctx.Init(); + sha256Pkt.context = sha256ctx; + sha384ctx.Init(); + sha384Pkt.context = sha384ctx; + sha512ctx.Init(); + sha512Pkt.context = sha512ctx; + ssctx.Init(); + spamsumPkt.context = ssctx; + + sectors = (ulong)(xmlTrk.EndSector - xmlTrk.StartSector + 1); + doneSectors = 0; + + while (doneSectors < sectors) + { + byte[] sector; + + if ((sectors - doneSectors) >= sectorsToRead) + { + sector = _imageFormat.ReadSectorsTag(doneSectors, sectorsToRead, (uint)xmlTrk.Sequence.TrackNumber, SectorTagType.CDSectorSubchannel); + DicConsole.Write("\rHashings subchannel sectors {0} to {2} of track {1} ({3} sectors)", doneSectors, xmlTrk.Sequence.TrackNumber, doneSectors + sectorsToRead, sectors); + doneSectors += sectorsToRead; + } + else + { + sector = _imageFormat.ReadSectorsTag(doneSectors, (uint)(sectors - doneSectors), (uint)xmlTrk.Sequence.TrackNumber, SectorTagType.CDSectorSubchannel); + DicConsole.Write("\rHashings subchannel sectors {0} to {2} of track {1} ({3} sectors)", doneSectors, xmlTrk.Sequence.TrackNumber, doneSectors + (sectors - doneSectors), sectors); + doneSectors += (sectors - doneSectors); + } + + adlerPkt.data = sector; + adlerThread.Start(adlerPkt); + crc16Pkt.data = sector; + crc16Thread.Start(crc16Pkt); + crc32Pkt.data = sector; + crc32Thread.Start(crc32Pkt); + crc64Pkt.data = sector; + crc64Thread.Start(crc64Pkt); + md5Pkt.data = sector; + md5Thread.Start(md5Pkt); + ripemd160Pkt.data = sector; + ripemd160Thread.Start(ripemd160Pkt); + sha1Pkt.data = sector; + sha1Thread.Start(sha1Pkt); + sha256Pkt.data = sector; + sha256Thread.Start(sha256Pkt); + sha384Pkt.data = sector; + sha384Thread.Start(sha384Pkt); + sha512Pkt.data = sector; + sha512Thread.Start(sha512Pkt); + spamsumPkt.data = sector; + spamsumThread.Start(spamsumPkt); + + while (adlerThread.IsAlive || crc16Thread.IsAlive || + crc32Thread.IsAlive || crc64Thread.IsAlive || + md5Thread.IsAlive || ripemd160Thread.IsAlive || + sha1Thread.IsAlive || sha256Thread.IsAlive || + sha384Thread.IsAlive || sha512Thread.IsAlive || + spamsumThread.IsAlive) + { + } + + adlerThread = new Thread(updateAdler); + crc16Thread = new Thread(updateCRC16); + crc32Thread = new Thread(updateCRC32); + crc64Thread = new Thread(updateCRC64); + md5Thread = new Thread(updateMD5); + ripemd160Thread = new Thread(updateRIPEMD160); + sha1Thread = new Thread(updateSHA1); + sha256Thread = new Thread(updateSHA256); + sha384Thread = new Thread(updateSHA384); + sha512Thread = new Thread(updateSHA512); + spamsumThread = new Thread(updateSpamSum); + } + + List subChecksums = new List(); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.adler32; + chk.Value = adler32ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc16; + chk.Value = crc16ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc32; + chk.Value = crc32ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.crc64; + chk.Value = crc64ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.md5; + chk.Value = md5ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.ripemd160; + chk.Value = ripemd160ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha1; + chk.Value = sha1ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha256; + chk.Value = sha256ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha384; + chk.Value = sha384ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.sha512; + chk.Value = sha512ctx.End(); + subChecksums.Add(chk); + + chk = new ChecksumType(); + chk.type = ChecksumTypeType.spamsum; + chk.Value = ssctx.End(); + subChecksums.Add(chk); + + xmlTrk.SubChannel.Checksums = subChecksums.ToArray(); + + DicConsole.WriteLine(); + } + + DicConsole.WriteLine("Checking filesystems on track {0} from sector {1} to {2}", xmlTrk.Sequence.TrackNumber, xmlTrk.StartSector, xmlTrk.EndSector); + + List partitions = new List(); + + foreach (PartPlugin _partplugin in plugins.PartPluginsList.Values) + { + List _partitions; + + if (_partplugin.GetInformation(_imageFormat, out _partitions)) + { + partitions = _partitions; + break; + } + } + + xmlTrk.FileSystemInformation = new PartitionType[1]; + if(partitions.Count > 0) + { + xmlTrk.FileSystemInformation = new PartitionType[partitions.Count]; + for(int i = 0; i < partitions.Count; i++) + { + xmlTrk.FileSystemInformation[i] = new PartitionType(); + xmlTrk.FileSystemInformation[i].Description = partitions[i].PartitionDescription; + xmlTrk.FileSystemInformation[i].EndSector = (int)(partitions[i].PartitionStartSector + partitions[i].PartitionSectors - 1); + xmlTrk.FileSystemInformation[i].Name = partitions[i].PartitionName; + xmlTrk.FileSystemInformation[i].Sequence = (int)partitions[i].PartitionSequence; + xmlTrk.FileSystemInformation[i].StartSector = (int)partitions[i].PartitionStartSector; + xmlTrk.FileSystemInformation[i].Type = partitions[i].PartitionType; + + List lstFs = new List(); + + foreach (Plugin _plugin in plugins.PluginsList.Values) + { + if (_plugin.Identify(_imageFormat, partitions[i].PartitionStartSector, partitions[i].PartitionStartSector+partitions[i].PartitionSectors-1)) + { + string foo; + _plugin.GetInformation(_imageFormat, partitions[i].PartitionStartSector, partitions[i].PartitionStartSector+partitions[i].PartitionSectors-1, out foo); + lstFs.Add(_plugin.XmlFSType); + } + } + + if(lstFs.Count > 0) + xmlTrk.FileSystemInformation[i].FileSystems = lstFs.ToArray(); + } + } + else + { + xmlTrk.FileSystemInformation[0] = new PartitionType(); + xmlTrk.FileSystemInformation[0].EndSector = (int)xmlTrk.EndSector; + xmlTrk.FileSystemInformation[0].StartSector = (int)xmlTrk.StartSector; + + List lstFs = new List(); + + foreach (Plugin _plugin in plugins.PluginsList.Values) + { + if (_plugin.Identify(_imageFormat, (ulong)xmlTrk.StartSector, (ulong)xmlTrk.EndSector)) + { + string foo; + _plugin.GetInformation(_imageFormat, (ulong)xmlTrk.StartSector, (ulong)xmlTrk.EndSector, out foo); + lstFs.Add(_plugin.XmlFSType); + } + } + + if(lstFs.Count > 0) + xmlTrk.FileSystemInformation[0].FileSystems = lstFs.ToArray(); + } + + trksLst.Add(xmlTrk); + } + + if (trksLst != null) + sidecar.OpticalDisc[0].Track = trksLst.ToArray(); + + break; + } + case XmlMediaType.BlockMedia: + { + sidecar.BlockMedia = new BlockMediaType[1]; + sidecar.BlockMedia[0] = new BlockMediaType(); + sidecar.BlockMedia[0].Checksums = imgChecksums.ToArray(); + sidecar.BlockMedia[0].Image = new ImageType(); + sidecar.BlockMedia[0].Image.format = _imageFormat.GetImageFormat(); + sidecar.BlockMedia[0].Image.offset = 0; + sidecar.BlockMedia[0].Image.offsetSpecified = true; + sidecar.BlockMedia[0].Image.Value = Path.GetFileName(options.InputFile); + sidecar.BlockMedia[0].Size = fi.Length; + sidecar.BlockMedia[0].Sequence = new SequenceType(); + if (_imageFormat.GetDiskSequence() != 0 && _imageFormat.GetLastDiskSequence() != 0) + { + sidecar.BlockMedia[0].Sequence.MediaSequence = _imageFormat.GetDiskSequence(); + sidecar.BlockMedia[0].Sequence.TotalMedia = _imageFormat.GetDiskSequence(); + } + else + { + sidecar.BlockMedia[0].Sequence.MediaSequence = 1; + sidecar.BlockMedia[0].Sequence.TotalMedia = 1; + } + sidecar.BlockMedia[0].Sequence.MediaTitle = _imageFormat.GetImageName(); + + //DiskType dskType = _imageFormat.ImageInfo.diskType; + // TODO: Complete it + break; + } + case XmlMediaType.LinearMedia: + { + sidecar.LinearMedia = new LinearMediaType[1]; + sidecar.LinearMedia[0] = new LinearMediaType(); + sidecar.LinearMedia[0].Checksums = imgChecksums.ToArray(); + sidecar.LinearMedia[0].Image = new ImageType(); + sidecar.LinearMedia[0].Image.format = _imageFormat.GetImageFormat(); + sidecar.LinearMedia[0].Image.offset = 0; + sidecar.LinearMedia[0].Image.offsetSpecified = true; + sidecar.LinearMedia[0].Image.Value = Path.GetFileName(options.InputFile); + sidecar.LinearMedia[0].Size = fi.Length; + + //DiskType dskType = _imageFormat.ImageInfo.diskType; + // TODO: Complete it + break; + } + case XmlMediaType.AudioMedia: + { + sidecar.AudioMedia = new AudioMediaType[1]; + sidecar.AudioMedia[0] = new AudioMediaType(); + sidecar.AudioMedia[0].Checksums = imgChecksums.ToArray(); + sidecar.AudioMedia[0].Image = new ImageType(); + sidecar.AudioMedia[0].Image.format = _imageFormat.GetImageFormat(); + sidecar.AudioMedia[0].Image.offset = 0; + sidecar.AudioMedia[0].Image.offsetSpecified = true; + sidecar.AudioMedia[0].Image.Value = Path.GetFileName(options.InputFile); + sidecar.AudioMedia[0].Size = fi.Length; + sidecar.AudioMedia[0].Sequence = new SequenceType(); + if (_imageFormat.GetDiskSequence() != 0 && _imageFormat.GetLastDiskSequence() != 0) + { + sidecar.AudioMedia[0].Sequence.MediaSequence = _imageFormat.GetDiskSequence(); + sidecar.AudioMedia[0].Sequence.TotalMedia = _imageFormat.GetDiskSequence(); + } + else + { + sidecar.AudioMedia[0].Sequence.MediaSequence = 1; + sidecar.AudioMedia[0].Sequence.TotalMedia = 1; + } + sidecar.AudioMedia[0].Sequence.MediaTitle = _imageFormat.GetImageName(); + + //DiskType dskType = _imageFormat.ImageInfo.diskType; + // TODO: Complete it + break; + } + + } + + DicConsole.WriteLine("Writing metadata sidecar"); + + FileStream xmlFs = new FileStream(Path.GetDirectoryName(options.InputFile) + + //Path.PathSeparator + + Path.GetFileNameWithoutExtension(options.InputFile) + ".cicm.xml", + FileMode.CreateNew); + + System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType)); + xmlSer.Serialize(xmlFs, sidecar); + xmlFs.Close(); + } + catch (Exception ex) + { + DicConsole.ErrorWriteLine(String.Format("Error reading file: {0}", ex.Message)); + DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); + } + } + + static string LbaToMsf(long lba) + { + long m, s, f; + if (lba >= -150) + { + m = (lba + 150) / (75 * 60); + lba -= m * (75 * 60); + s = (lba + 150) / 75; + lba -= s * 75; + f = lba + 150; + } + else + { + m = (lba + 450150) / (75 * 60); + lba -= m * (75 * 60); + s = (lba + 450150) / 75; + lba -= s * 75; + f = lba + 450150; + } + + return String.Format("{0}:{1:D2}:{2:D2}", m, s, f); + } + + static string DdcdLbaToMsf(long lba) + { + long h, m, s, f; + if (lba >= -150) + { + h = (lba + 150) / (75 * 60 * 60); + lba -= h * (75 * 60 * 60); + m = (lba + 150) / (75 * 60); + lba -= m * (75 * 60); + s = (lba + 150) / 75; + lba -= s * 75; + f = lba + 150; + } + else + { + h = (lba + 450150 * 2) / (75 * 60 * 60); + lba -= h * (75 * 60 * 60); + m = (lba + 450150 * 2) / (75 * 60); + lba -= m * (75 * 60); + s = (lba + 450150 * 2) / 75; + lba -= s * 75; + f = lba + 450150 * 2; + } + + return String.Format("{3}:{0:D2}:{1:D2}:{2:D2}", m, s, f, h); + } + + static List GetChecksums(byte[] data) + { + Adler32Context adler32ctx = new Adler32Context(); + CRC16Context crc16ctx = new CRC16Context(); + CRC32Context crc32ctx = new CRC32Context(); + CRC64Context crc64ctx = new CRC64Context(); + MD5Context md5ctx = new MD5Context(); + RIPEMD160Context ripemd160ctx = new RIPEMD160Context(); + SHA1Context sha1ctx = new SHA1Context(); + SHA256Context sha256ctx = new SHA256Context(); + SHA384Context sha384ctx = new SHA384Context(); + SHA512Context sha512ctx = new SHA512Context(); + SpamSumContext ssctx = new SpamSumContext(); + + Thread adlerThread = new Thread(updateAdler); + Thread crc16Thread = new Thread(updateCRC16); + Thread crc32Thread = new Thread(updateCRC32); + Thread crc64Thread = new Thread(updateCRC64); + Thread md5Thread = new Thread(updateMD5); + Thread ripemd160Thread = new Thread(updateRIPEMD160); + Thread sha1Thread = new Thread(updateSHA1); + Thread sha256Thread = new Thread(updateSHA256); + Thread sha384Thread = new Thread(updateSHA384); + Thread sha512Thread = new Thread(updateSHA512); + Thread spamsumThread = new Thread(updateSpamSum); + + adlerPacket adlerPkt = new adlerPacket(); + crc16Packet crc16Pkt = new crc16Packet(); + crc32Packet crc32Pkt = new crc32Packet(); + crc64Packet crc64Pkt = new crc64Packet(); + md5Packet md5Pkt = new md5Packet(); + ripemd160Packet ripemd160Pkt = new ripemd160Packet(); + sha1Packet sha1Pkt = new sha1Packet(); + sha256Packet sha256Pkt = new sha256Packet(); + sha384Packet sha384Pkt = new sha384Packet(); + sha512Packet sha512Pkt = new sha512Packet(); + spamsumPacket spamsumPkt = new spamsumPacket(); + + adler32ctx.Init(); + adlerPkt.context = adler32ctx; + crc16ctx.Init(); + crc16Pkt.context = crc16ctx; + crc32ctx.Init(); + crc32Pkt.context = crc32ctx; + crc64ctx.Init(); + crc64Pkt.context = crc64ctx; + md5ctx.Init(); + md5Pkt.context = md5ctx; + ripemd160ctx.Init(); + ripemd160Pkt.context = ripemd160ctx; + sha1ctx.Init(); + sha1Pkt.context = sha1ctx; + sha256ctx.Init(); + sha256Pkt.context = sha256ctx; + sha384ctx.Init(); + sha384Pkt.context = sha384ctx; + sha512ctx.Init(); + sha512Pkt.context = sha512ctx; + ssctx.Init(); + spamsumPkt.context = ssctx; + + adlerPkt.data = data; + adlerThread.Start(adlerPkt); + crc16Pkt.data = data; + crc16Thread.Start(crc16Pkt); + crc32Pkt.data = data; + crc32Thread.Start(crc32Pkt); + crc64Pkt.data = data; + crc64Thread.Start(crc64Pkt); + md5Pkt.data = data; + md5Thread.Start(md5Pkt); + ripemd160Pkt.data = data; + ripemd160Thread.Start(ripemd160Pkt); + sha1Pkt.data = data; + sha1Thread.Start(sha1Pkt); + sha256Pkt.data = data; + sha256Thread.Start(sha256Pkt); + sha384Pkt.data = data; + sha384Thread.Start(sha384Pkt); + sha512Pkt.data = data; + sha512Thread.Start(sha512Pkt); + spamsumPkt.data = data; + spamsumThread.Start(spamsumPkt); + + while (adlerThread.IsAlive || crc16Thread.IsAlive || + crc32Thread.IsAlive || crc64Thread.IsAlive || + md5Thread.IsAlive || ripemd160Thread.IsAlive || + sha1Thread.IsAlive || sha256Thread.IsAlive || + sha384Thread.IsAlive || sha512Thread.IsAlive || + spamsumThread.IsAlive) + { + } + + List imgChecksums = new List(); + ChecksumType chk = new ChecksumType(); + + chk.type = ChecksumTypeType.adler32; + chk.Value = adler32ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.crc16; + chk.Value = crc16ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.crc32; + chk.Value = crc32ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.crc64; + chk.Value = crc64ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.md5; + chk.Value = md5ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.ripemd160; + chk.Value = ripemd160ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.sha1; + chk.Value = sha1ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.sha256; + chk.Value = sha256ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.sha384; + chk.Value = sha384ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.sha512; + chk.Value = sha512ctx.End(); + imgChecksums.Add(chk); + + chk.type = ChecksumTypeType.spamsum; + chk.Value = ssctx.End(); + imgChecksums.Add(chk); + + return imgChecksums; + } + + #region Threading helpers + + struct adlerPacket + { + public Adler32Context context; + public byte[] data; + } + + struct crc16Packet + { + public CRC16Context context; + public byte[] data; + } + + struct crc32Packet + { + public CRC32Context context; + public byte[] data; + } + + struct crc64Packet + { + public CRC64Context context; + public byte[] data; + } + + /*struct fletcher16Packet + { + public Fletcher16Context context; + public byte[] data; + } + + struct fletcher32Packet + { + public Fletcher32Context context; + public byte[] data; + }*/ + + struct md5Packet + { + public MD5Context context; + public byte[] data; + } + + struct ripemd160Packet + { + public RIPEMD160Context context; + public byte[] data; + } + + struct sha1Packet + { + public SHA1Context context; + public byte[] data; + } + + struct sha256Packet + { + public SHA256Context context; + public byte[] data; + } + + struct sha384Packet + { + public SHA384Context context; + public byte[] data; + } + + struct sha512Packet + { + public SHA512Context context; + public byte[] data; + } + + struct spamsumPacket + { + public SpamSumContext context; + public byte[] data; + } + + static void updateAdler(object packet) + { + ((adlerPacket)packet).context.Update(((adlerPacket)packet).data); + } + + static void updateCRC16(object packet) + { + ((crc16Packet)packet).context.Update(((crc16Packet)packet).data); + } + + static void updateCRC32(object packet) + { + ((crc32Packet)packet).context.Update(((crc32Packet)packet).data); + } + + static void updateCRC64(object packet) + { + ((crc64Packet)packet).context.Update(((crc64Packet)packet).data); + } + + /*static void updateFletcher16(object packet) + { + ((fletcher16Packet)packet).context.Update(((fletcher16Packet)packet).data); + } + + static void updateFletcher32(object packet) + { + ((fletcher32Packet)packet).context.Update(((fletcher32Packet)packet).data); + }*/ + + static void updateMD5(object packet) + { + ((md5Packet)packet).context.Update(((md5Packet)packet).data); + } + + static void updateRIPEMD160(object packet) + { + ((ripemd160Packet)packet).context.Update(((ripemd160Packet)packet).data); + } + + static void updateSHA1(object packet) + { + ((sha1Packet)packet).context.Update(((sha1Packet)packet).data); + } + + static void updateSHA256(object packet) + { + ((sha256Packet)packet).context.Update(((sha256Packet)packet).data); + } + + static void updateSHA384(object packet) + { + ((sha384Packet)packet).context.Update(((sha384Packet)packet).data); + } + + static void updateSHA512(object packet) + { + ((sha512Packet)packet).context.Update(((sha512Packet)packet).data); + } + + static void updateSpamSum(object packet) + { + ((spamsumPacket)packet).context.Update(((spamsumPacket)packet).data); + } + + #endregion Threading helpers + } } diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index ad363ad1d..f24effaa4 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -34,6 +34,7 @@ + @@ -55,6 +56,7 @@ False + @@ -190,5 +192,9 @@ {CCAA7AFE-C094-4D82-A66D-630DE8A3F545} DiscImageChef.Console + + {9F213318-5CB8-4066-A757-074489C9F818} + DiscImageChef.Metadata + \ No newline at end of file diff --git a/DiscImageChef/Main.cs b/DiscImageChef/Main.cs index f86480a56..ab5045f94 100644 --- a/DiscImageChef/Main.cs +++ b/DiscImageChef/Main.cs @@ -170,6 +170,14 @@ namespace DiscImageChef DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; Commands.Benchmark.doBenchmark(BenchmarkOptions); break; + case "create-sidecar": + CreateSidecarSubOptions CreateSidecarOptions = (CreateSidecarSubOptions)invokedVerbInstance; + if (CreateSidecarOptions.Debug) + DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; + if (CreateSidecarOptions.Verbose) + DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; + Commands.CreateSidecar.doSidecar(CreateSidecarOptions); + break; default: throw new ArgumentException("Should never arrive here!"); } diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs index a5262704c..b54949a60 100644 --- a/DiscImageChef/Options.cs +++ b/DiscImageChef/Options.cs @@ -245,6 +245,12 @@ namespace DiscImageChef public int BufferSize { get; set; } } + public class CreateSidecarSubOptions : CommonSubOptions + { + [Option('i', "input", Required = true, HelpText = "Disc image.")] + public string InputFile { get; set; } + } + public class Options { public Options() @@ -259,7 +265,8 @@ namespace DiscImageChef DecodeVerb = new DecodeSubOptions(); DeviceInfoVerb = new DeviceInfoSubOptions(); MediaInfoVerb = new MediaInfoSubOptions(); - BenchmarkInfoVerb = new BenchmarkSubOptions(); + BenchmarkVerb = new BenchmarkSubOptions(); + CreateSidecarVerb = new CreateSidecarSubOptions(); } [VerbOption("analyze", HelpText = "Analyzes a disc image and searches for partitions and/or filesystems.")] @@ -293,7 +300,10 @@ namespace DiscImageChef public MediaInfoSubOptions MediaInfoVerb { get; set; } [VerbOption("benchmark", HelpText = "Benchmarks hashing and entropy calculation.")] - public BenchmarkSubOptions BenchmarkInfoVerb { get; set; } + public BenchmarkSubOptions BenchmarkVerb { get; set; } + + [VerbOption("create-sidecar", HelpText = "Creates CICM Metadata XML sidecar.")] + public CreateSidecarSubOptions CreateSidecarVerb { get; set; } [HelpVerbOption] public string DoHelpForVerb(string verbName)