diff --git a/DiscImageChef.CommonTypes.csproj b/DiscImageChef.CommonTypes.csproj
index a130725..f396d69 100644
--- a/DiscImageChef.CommonTypes.csproj
+++ b/DiscImageChef.CommonTypes.csproj
@@ -46,10 +46,46 @@
+
+ Metadata/cicm.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -60,6 +96,14 @@
+
+
+ LICENSE.MIT
+
+
+
+
+
diff --git a/Enums/Images.cs b/Enums/Images.cs
new file mode 100644
index 0000000..372ca59
--- /dev/null
+++ b/Enums/Images.cs
@@ -0,0 +1,356 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : Enums.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Disc image plugins.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Defines enumerations to be used by disc image plugins.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+
+namespace DiscImageChef.CommonTypes.Enums
+{
+ ///
+ /// Track (as partitioning element) types.
+ ///
+ public enum TrackType : byte
+ {
+ /// Audio track
+ Audio = 0,
+ /// Data track (not any of the below defined ones)
+ Data = 1,
+ /// Data track, compact disc mode 1
+ CdMode1 = 2,
+ /// Data track, compact disc mode 2, formless
+ CdMode2Formless = 3,
+ /// Data track, compact disc mode 2, form 1
+ CdMode2Form1 = 4,
+ /// Data track, compact disc mode 2, form 2
+ CdMode2Form2 = 5
+ }
+
+ ///
+ /// Type of subchannel in track
+ ///
+ public enum TrackSubchannelType
+ {
+ ///
+ /// Track does not has subchannel dumped, or it's not a CD
+ ///
+ None,
+ ///
+ /// Subchannel is packed and error corrected
+ ///
+ Packed,
+ ///
+ /// Subchannel is interleaved
+ ///
+ Raw,
+ ///
+ /// Subchannel is packed and comes interleaved with main channel in same file
+ ///
+ PackedInterleaved,
+ ///
+ /// Subchannel is interleaved and comes interleaved with main channel in same file
+ ///
+ RawInterleaved,
+ ///
+ /// Only Q subchannel is stored as 16 bytes
+ ///
+ Q16,
+ ///
+ /// Only Q subchannel is stored as 16 bytes and comes interleaved with main channel in same file
+ ///
+ Q16Interleaved
+ }
+
+ ///
+ /// Metadata present for each sector (aka, "tag").
+ ///
+ public enum SectorTagType
+ {
+ /// Apple's GCR sector tags, 12 bytes
+ AppleSectorTag,
+ /// Sync frame from CD sector, 12 bytes
+ CdSectorSync,
+ /// CD sector header, 4 bytes
+ CdSectorHeader,
+ /// CD mode 2 sector subheader
+ CdSectorSubHeader,
+ /// CD sector EDC, 4 bytes
+ CdSectorEdc,
+ /// CD sector ECC P, 172 bytes
+ CdSectorEccP,
+ /// CD sector ECC Q, 104 bytes
+ CdSectorEccQ,
+ /// CD sector ECC (P and Q), 276 bytes
+ CdSectorEcc,
+ /// CD sector subchannel, 96 bytes
+ CdSectorSubchannel,
+ /// CD track ISRC, string, 12 bytes
+ CdTrackIsrc,
+ /// CD track text, string, 13 bytes
+ CdTrackText,
+ /// CD track flags, 1 byte
+ CdTrackFlags,
+ /// DVD sector copyright information
+ DvdCmi,
+ /// Floppy address mark (contents depend on underlying floppy format)
+ FloppyAddressMark
+ }
+
+ ///
+ /// Metadata present for each media.
+ ///
+ public enum MediaTagType
+ {
+ /// CD table of contents
+ CD_TOC,
+ /// CD session information
+ CD_SessionInfo,
+ /// CD full table of contents
+ CD_FullTOC,
+ /// CD PMA
+ CD_PMA,
+ /// CD Adress-Time-In-Pregroove
+ CD_ATIP,
+ /// CD-Text
+ CD_TEXT,
+ /// CD Media Catalogue Number
+ CD_MCN,
+ /// DVD/HD DVD Physical Format Information
+ DVD_PFI,
+ /// DVD Lead-in Copyright Management Information
+ DVD_CMI,
+ /// DVD disc key
+ DVD_DiscKey,
+ /// DVD/HD DVD Burst Cutting Area
+ DVD_BCA,
+ /// DVD/HD DVD Lead-in Disc Manufacturer Information
+ DVD_DMI,
+ /// Media identifier
+ DVD_MediaIdentifier,
+ /// Media key block
+ DVD_MKB,
+ /// DVD-RAM/HD DVD-RAM DDS information
+ DVDRAM_DDS,
+ /// DVD-RAM/HD DVD-RAM Medium status
+ DVDRAM_MediumStatus,
+ /// DVD-RAM/HD DVD-RAM Spare area information
+ DVDRAM_SpareArea,
+ /// DVD-R/-RW/HD DVD-R RMD in last border-out
+ DVDR_RMD,
+ /// Pre-recorded information from DVD-R/-RW lead-in
+ DVDR_PreRecordedInfo,
+ /// DVD-R/-RW/HD DVD-R media identifier
+ DVDR_MediaIdentifier,
+ /// DVD-R/-RW/HD DVD-R physical format information
+ DVDR_PFI,
+ /// ADIP information
+ DVD_ADIP,
+ /// HD DVD Lead-in copyright protection information
+ HDDVD_CPI,
+ /// HD DVD-R Medium Status
+ HDDVD_MediumStatus,
+ /// DVD+/-R DL Layer capacity
+ DVDDL_LayerCapacity,
+ /// DVD-R DL Middle Zone start address
+ DVDDL_MiddleZoneAddress,
+ /// DVD-R DL Jump Interval Size
+ DVDDL_JumpIntervalSize,
+ /// DVD-R DL Start LBA of the manual layer jump
+ DVDDL_ManualLayerJumpLBA,
+ /// Blu-ray Disc Information
+ BD_DI,
+ /// Blu-ray Burst Cutting Area
+ BD_BCA,
+ /// Blu-ray Disc Definition Structure
+ BD_DDS,
+ /// Blu-ray Cartridge Status
+ BD_CartridgeStatus,
+ /// Blu-ray Status of Spare Area
+ BD_SpareArea,
+ /// AACS volume identifier
+ AACS_VolumeIdentifier,
+ /// AACS pre-recorded media serial number
+ AACS_SerialNumber,
+ /// AACS media identifier
+ AACS_MediaIdentifier,
+ /// Lead-in AACS media key block
+ AACS_MKB,
+ /// AACS data keys
+ AACS_DataKeys,
+ /// LBA extents flagged for bus encryption by AACS
+ AACS_LBAExtents,
+ /// CPRM media key block in Lead-in
+ AACS_CPRM_MKB,
+ /// Recognized layer formats in hybrid discs
+ Hybrid_RecognizedLayers,
+ /// Disc write protection status
+ MMC_WriteProtection,
+ /// Disc standard information
+ MMC_DiscInformation,
+ /// Disc track resources information
+ MMC_TrackResourcesInformation,
+ /// BD-R Pseudo-overwrite information
+ MMC_POWResourcesInformation,
+ /// SCSI INQUIRY response
+ SCSI_INQUIRY,
+ /// SCSI MODE PAGE 2Ah
+ SCSI_MODEPAGE_2A,
+ /// ATA IDENTIFY DEVICE response
+ ATA_IDENTIFY,
+ /// ATA IDENTIFY PACKET DEVICE response
+ ATAPI_IDENTIFY,
+ /// PCMCIA/CardBus Card Information Structure
+ PCMCIA_CIS,
+ /// SecureDigital CID
+ SD_CID,
+ /// SecureDigital CSD
+ SD_CSD,
+ /// SecureDigital SCR
+ SD_SCR,
+ /// SecureDigital OCR
+ SD_OCR,
+ /// MultiMediaCard CID
+ MMC_CID,
+ /// MultiMediaCard CSD
+ MMC_CSD,
+ /// MultiMediaCard OCR
+ MMC_OCR,
+ /// MultiMediaCard Extended CSD
+ MMC_ExtendedCSD,
+ /// Xbox Security Sector
+ Xbox_SecuritySector,
+ ///
+ /// On floppy disks, data in last cylinder usually in a different format that contains duplication or
+ /// manufacturing information
+ ///
+ Floppy_LeadOut,
+ /// DVD Disc Control Blocks
+ DCB,
+ /// Compact Disc Lead-in
+ CD_LeadIn,
+ /// Compact Disc Lead-out
+ CD_LeadOut,
+ /// SCSI MODE SENSE (6)
+ SCSI_MODESENSE_6,
+ /// SCSI MODE SENSE (10)
+ SCSI_MODESENSE_10,
+ /// USB descriptors
+ USB_Descriptors,
+ /// XGD unlocked DMI
+ Xbox_DMI,
+ /// XDG unlocked PFI
+ Xbox_PFI
+ }
+
+ ///
+ /// Enumeration of media types defined in CICM metadata
+ ///
+ public enum XmlMediaType
+ {
+ ///
+ /// Purely optical discs
+ ///
+ OpticalDisc,
+ ///
+ /// Media that is physically block-based or abstracted like that
+ ///
+ BlockMedia,
+ ///
+ /// Media that can be accessed by-byte or by-bit, like chips
+ ///
+ LinearMedia,
+ ///
+ /// Media that can only store data when it is modulated to audio
+ ///
+ AudioMedia
+ }
+
+ /// CD flags bitmask
+ [Flags]
+ public enum CdFlags : byte
+ {
+ /// Track is quadraphonic.
+ FourChannel = 0x08,
+ /// Track is non-audio (data).
+ DataTrack = 0x04,
+ /// Track is copy protected.
+ CopyPermitted = 0x02,
+ /// Track has pre-emphasis.
+ PreEmphasis = 0x01
+ }
+
+ /// Status of a requested floppy sector
+ [Flags]
+ public enum FloppySectorStatus : byte
+ {
+ /// Both address mark and data checksums are correct.
+ Correct = 0x01,
+ /// Data checksum is incorrect.
+ DataError = 0x02,
+ /// Addres mark checksum is incorrect.
+ AddressMarkError = 0x04,
+ /// There is another sector in the same track/head with same sector id.
+ Duplicated = 0x08,
+ /// Sector data section is not magnetized.
+ Demagnetized = 0x10,
+ /// Sector data section has a physically visible hole.
+ Hole = 0x20,
+ /// There is no address mark containing the requested sector id in the track/head.
+ NotFound = 0x40
+ }
+
+ public enum FloppyTypes : byte
+ {
+ /// 8" floppy
+ Floppy,
+ /// 5.25" floppy
+ MiniFloppy,
+ /// 3.5" floppy
+ MicroFloppy,
+ /// 3" floppy
+ CompactFloppy,
+ /// 5.25" twiggy
+ FileWare,
+ /// 2.5" quickdisk
+ QuickDisk
+ }
+
+ public enum FloppyDensities : byte
+ {
+ /// Standard coercitivity (about 300Oe as found in 8" and 5.25"-double-density disks).
+ Standard,
+ /// Double density coercitivity (about 600Oe as found in 5.25" HD and 3.5" DD disks).
+ Double,
+ /// High density coercitivity (about 700Oe as found in 3.5" HD disks).
+ High,
+ /// Extended density coercitivity (about 750Oe as found in 3.5" ED disks).
+ Extended
+ }
+}
\ No newline at end of file
diff --git a/Exceptions/Images.cs b/Exceptions/Images.cs
new file mode 100644
index 0000000..e724f90
--- /dev/null
+++ b/Exceptions/Images.cs
@@ -0,0 +1,188 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : Enums.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Disc image plugins.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Defines exceptions to be thrown by disc image plugins.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Runtime.Serialization;
+
+namespace DiscImageChef.CommonTypes.Exceptions
+{
+ ///
+ /// Feature is supported by image but not implemented yet.
+ ///
+ [Serializable]
+ public class FeatureSupportedButNotImplementedImageException : Exception
+ {
+ ///
+ /// Feature is supported by image but not implemented yet.
+ ///
+ /// Message.
+ /// Inner.
+ public FeatureSupportedButNotImplementedImageException(string message, Exception inner) :
+ base(message, inner) { }
+
+ ///
+ /// Feature is supported by image but not implemented yet.
+ ///
+ /// Message.
+ public FeatureSupportedButNotImplementedImageException(string message) : base(message) { }
+
+ ///
+ /// Feature is supported by image but not implemented yet.
+ ///
+ /// Info.
+ /// Context.
+ protected FeatureSupportedButNotImplementedImageException(SerializationInfo info, StreamingContext context)
+ {
+ if(info == null) throw new ArgumentNullException(nameof(info));
+ }
+ }
+
+ ///
+ /// Feature is not supported by image.
+ ///
+ [Serializable]
+ public class FeatureUnsupportedImageException : Exception
+ {
+ ///
+ /// Feature is not supported by image.
+ ///
+ /// Message.
+ /// Inner.
+ public FeatureUnsupportedImageException(string message, Exception inner) : base(message, inner) { }
+
+ ///
+ /// Feature is not supported by image.
+ ///
+ /// Message.
+ public FeatureUnsupportedImageException(string message) : base(message) { }
+
+ ///
+ /// Feature is not supported by image.
+ ///
+ /// Info.
+ /// Context.
+ protected FeatureUnsupportedImageException(SerializationInfo info, StreamingContext context)
+ {
+ if(info == null) throw new ArgumentNullException(nameof(info));
+ }
+ }
+
+ ///
+ /// Feature is supported by image but not present on it.
+ ///
+ [Serializable]
+ public class FeatureNotPresentImageException : Exception
+ {
+ ///
+ /// Feature is supported by image but not present on it.
+ ///
+ /// Message.
+ /// Inner.
+ public FeatureNotPresentImageException(string message, Exception inner) : base(message, inner) { }
+
+ ///
+ /// Feature is supported by image but not present on it.
+ ///
+ /// Message.
+ public FeatureNotPresentImageException(string message) : base(message) { }
+
+ ///
+ /// Feature is supported by image but not present on it.
+ ///
+ /// Info.
+ /// Context.
+ protected FeatureNotPresentImageException(SerializationInfo info, StreamingContext context)
+ {
+ if(info == null) throw new ArgumentNullException(nameof(info));
+ }
+ }
+
+ ///
+ /// Feature is supported by image but not by the disc it represents.
+ ///
+ [Serializable]
+ public class FeaturedNotSupportedByDiscImageException : Exception
+ {
+ ///
+ /// Feature is supported by image but not by the disc it represents.
+ ///
+ /// Message.
+ /// Inner.
+ public FeaturedNotSupportedByDiscImageException(string message, Exception inner) : base(message, inner) { }
+
+ ///
+ /// Feature is supported by image but not by the disc it represents.
+ ///
+ /// Message.
+ public FeaturedNotSupportedByDiscImageException(string message) : base(message) { }
+
+ ///
+ /// Feature is supported by image but not by the disc it represents.
+ ///
+ /// Info.
+ /// Context.
+ protected FeaturedNotSupportedByDiscImageException(SerializationInfo info, StreamingContext context)
+ {
+ if(info == null) throw new ArgumentNullException(nameof(info));
+ }
+ }
+
+ ///
+ /// Corrupt, incorrect or unhandled feature found on image
+ ///
+ [Serializable]
+ public class ImageNotSupportedException : Exception
+ {
+ ///
+ /// Corrupt, incorrect or unhandled feature found on image
+ ///
+ /// Message.
+ /// Inner.
+ public ImageNotSupportedException(string message, Exception inner) : base(message, inner) { }
+
+ ///
+ /// Corrupt, incorrect or unhandled feature found on image
+ ///
+ /// Message.
+ public ImageNotSupportedException(string message) : base(message) { }
+
+ ///
+ /// Corrupt, incorrect or unhandled feature found on image
+ ///
+ /// Info.
+ /// Context.
+ protected ImageNotSupportedException(SerializationInfo info, StreamingContext context)
+ {
+ if(info == null) throw new ArgumentNullException(nameof(info));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsByte.cs b/Extents/ExtentsByte.cs
new file mode 100644
index 0000000..e51e215
--- /dev/null
+++ b/Extents/ExtentsByte.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsByte.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for byte types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsByte
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsByte()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsByte(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(byte item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(byte start, byte end, bool run = false)
+ {
+ byte realEnd;
+ if(run) realEnd = (byte)(start + end - 1);
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(byte t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(byte item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(byte item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (byte)(item - 1));
+ toAddTwo = new Tuple((byte)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple((byte)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (byte)(item - 1));
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(byte item, out byte start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsConverter.cs b/Extents/ExtentsConverter.cs
new file mode 100644
index 0000000..1739b44
--- /dev/null
+++ b/Extents/ExtentsConverter.cs
@@ -0,0 +1,65 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsConverter.cs
+// Author(s) : Natalia Portillo
+//
+// Component : XML metadata.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Converts extents to/from XML.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Schemas;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ public static class ExtentsConverter
+ {
+ public static ExtentType[] ToMetadata(ExtentsULong extents)
+ {
+ if(extents == null) return null;
+
+ Tuple[] tuples = extents.ToArray();
+ ExtentType[] array = new ExtentType[tuples.Length];
+
+ for(ulong i = 0; i < (ulong)array.LongLength; i++)
+ array[i] = new ExtentType {Start = tuples[i].Item1, End = tuples[i].Item2};
+
+ return array;
+ }
+
+ public static ExtentsULong FromMetadata(ExtentType[] extents)
+ {
+ if(extents == null) return null;
+
+ List> tuples =
+ extents.Select(extent => new Tuple(extent.Start, extent.End)).ToList();
+
+ return new ExtentsULong(tuples);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsInt.cs b/Extents/ExtentsInt.cs
new file mode 100644
index 0000000..7f7e7d3
--- /dev/null
+++ b/Extents/ExtentsInt.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsInt.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for int types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License aint with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsInt
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsInt()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsInt(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(int item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(int start, int end, bool run = false)
+ {
+ int realEnd;
+ if(run) realEnd = start + end - 1;
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(int t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(int item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(int item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ toAddTwo = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(int item, out int start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsLong.cs b/Extents/ExtentsLong.cs
new file mode 100644
index 0000000..fa401de
--- /dev/null
+++ b/Extents/ExtentsLong.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsLong.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for long types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsLong
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsLong()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsLong(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(long item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(long start, long end, bool run = false)
+ {
+ long realEnd;
+ if(run) realEnd = start + end - 1;
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(long t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(long item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(long item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ toAddTwo = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(long item, out long start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsSByte.cs b/Extents/ExtentsSByte.cs
new file mode 100644
index 0000000..e740dbe
--- /dev/null
+++ b/Extents/ExtentsSByte.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsSByte.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for sbyte types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsSByte
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsSByte()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsSByte(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(sbyte item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(sbyte start, sbyte end, bool run = false)
+ {
+ sbyte realEnd;
+ if(run) realEnd = (sbyte)(start + end - 1);
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(sbyte t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(sbyte item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(sbyte item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (sbyte)(item - 1));
+ toAddTwo = new Tuple((sbyte)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple((sbyte)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (sbyte)(item - 1));
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(sbyte item, out sbyte start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsShort.cs b/Extents/ExtentsShort.cs
new file mode 100644
index 0000000..bc677e2
--- /dev/null
+++ b/Extents/ExtentsShort.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsShort.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for short types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License ashort with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsShort
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsShort()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsShort(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(short item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(short start, short end, bool run = false)
+ {
+ short realEnd;
+ if(run) realEnd = (short)(start + end - 1);
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(short t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(short item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(short item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (short)(item - 1));
+ toAddTwo = new Tuple((short)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple((short)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (short)(item - 1));
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(short item, out short start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsUInt.cs b/Extents/ExtentsUInt.cs
new file mode 100644
index 0000000..7f092cb
--- /dev/null
+++ b/Extents/ExtentsUInt.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsUInt.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for uint types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License auint with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsUInt
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsUInt()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsUInt(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(uint item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(uint start, uint end, bool run = false)
+ {
+ uint realEnd;
+ if(run) realEnd = start + end - 1;
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(uint t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(uint item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(uint item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ toAddTwo = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(uint item, out uint start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsULong.cs b/Extents/ExtentsULong.cs
new file mode 100644
index 0000000..c999dba
--- /dev/null
+++ b/Extents/ExtentsULong.cs
@@ -0,0 +1,248 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsULong.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for ulong types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License aulong with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsULong
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsULong()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsULong(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(ulong item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(ulong start, ulong end, bool run = false)
+ {
+ ulong realEnd;
+ if(run) realEnd = start + end - 1;
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(ulong t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(ulong item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(ulong item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ toAddTwo = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(item + 1, extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, item - 1);
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(ulong item, out ulong start)
+ {
+ start = 0;
+ foreach(Tuple extent in backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extents/ExtentsUShort.cs b/Extents/ExtentsUShort.cs
new file mode 100644
index 0000000..6ee6894
--- /dev/null
+++ b/Extents/ExtentsUShort.cs
@@ -0,0 +1,249 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsUShort.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Extent helpers.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides extents for ushort types.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License aushort with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DiscImageChef.CommonTypes.Extents
+{
+ ///
+ /// Implements extents for
+ ///
+ public class ExtentsUShort
+ {
+ List> backend;
+
+ ///
+ /// Initialize an empty list of extents
+ ///
+ public ExtentsUShort()
+ {
+ backend = new List>();
+ }
+
+ ///
+ /// Initializes extents with an specific list
+ ///
+ /// List of extents as tuples "start, end"
+ public ExtentsUShort(IEnumerable> list)
+ {
+ backend = list.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Gets a count of how many extents are stored
+ ///
+ public int Count => backend.Count;
+
+ ///
+ /// Adds the specified number to the corresponding extent, or creates a new one
+ ///
+ ///
+ public void Add(ushort item)
+ {
+ Tuple removeOne = null;
+ Tuple removeTwo = null;
+ Tuple itemToAdd = null;
+
+ for(int i = 0; i < backend.Count; i++)
+ {
+ // Already contained in an extent
+ if(item >= backend[i].Item1 && item <= backend[i].Item2) return;
+
+ // Expands existing extent start
+ if(item == backend[i].Item1 - 1)
+ {
+ removeOne = backend[i];
+
+ if(i > 0 && item == backend[i - 1].Item2 + 1)
+ {
+ removeTwo = backend[i - 1];
+ itemToAdd = new Tuple(backend[i - 1].Item1, backend[i].Item2);
+ }
+ else itemToAdd = new Tuple(item, backend[i].Item2);
+
+ break;
+ }
+
+ // Expands existing extent end
+ if(item != backend[i].Item2 + 1) continue;
+
+ removeOne = backend[i];
+
+ if(i < backend.Count - 1 && item == backend[i + 1].Item1 - 1)
+ {
+ removeTwo = backend[i + 1];
+ itemToAdd = new Tuple(backend[i].Item1, backend[i + 1].Item2);
+ }
+ else itemToAdd = new Tuple(backend[i].Item1, item);
+
+ break;
+ }
+
+ if(itemToAdd != null)
+ {
+ backend.Remove(removeOne);
+ backend.Remove(removeTwo);
+ backend.Add(itemToAdd);
+ }
+ else backend.Add(new Tuple(item, item));
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+ }
+
+ ///
+ /// Adds a new extent
+ ///
+ /// First element of the extent
+ ///
+ /// Last element of the extent or if is true how many elements the extent runs
+ /// for
+ ///
+ /// If set to true, indicates how many elements the extent runs for
+ public void Add(ushort start, ushort end, bool run = false)
+ {
+ ushort realEnd;
+ if(run) realEnd = (ushort)(start + end - 1);
+ else realEnd = end;
+
+ // TODO: Optimize this
+ for(ushort t = start; t <= realEnd; t++) Add(t);
+ }
+
+ ///
+ /// Checks if the specified item is contained by an extent on this instance
+ ///
+ /// Item to seach for
+ /// true if any of the extents on this instance contains the item
+ public bool Contains(ushort item)
+ {
+ return backend.Any(extent => item >= extent.Item1 && item <= extent.Item2);
+ }
+
+ ///
+ /// Removes all extents from this instance
+ ///
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ ///
+ /// Removes an item from the extents in this instance
+ ///
+ /// Item to remove
+ /// true if the item was contained in a known extent and removed, false otherwise
+ public bool Remove(ushort item)
+ {
+ Tuple toRemove = null;
+ Tuple toAddOne = null;
+ Tuple toAddTwo = null;
+
+ foreach(Tuple extent in backend)
+ {
+ // Extent is contained and not a border
+ if(item > extent.Item1 && item < extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (ushort)(item - 1));
+ toAddTwo = new Tuple((ushort)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is left border, but not only element
+ if(item == extent.Item1 && item != extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple((ushort)(item + 1), extent.Item2);
+ break;
+ }
+
+ // Extent is right border, but not only element
+ if(item != extent.Item1 && item == extent.Item2)
+ {
+ toRemove = extent;
+ toAddOne = new Tuple(extent.Item1, (ushort)(item - 1));
+ break;
+ }
+
+ // Extent is only element
+ if(item != extent.Item1 || item != extent.Item2) continue;
+
+ toRemove = extent;
+ break;
+ }
+
+ // Item not found
+ if(toRemove == null) return false;
+
+ backend.Remove(toRemove);
+ if(toAddOne != null) backend.Add(toAddOne);
+ if(toAddTwo != null) backend.Add(toAddTwo);
+
+ // Sort
+ backend = backend.OrderBy(t => t.Item1).ToList();
+
+ return true;
+ }
+
+ ///
+ /// Converts the list of extents to an array of where T1 is first element of the extent and T2 is
+ /// last element
+ ///
+ /// Array of
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+
+ ///
+ /// Gets the first element of the extent that contains the specified item
+ ///
+ /// Item
+ /// First element of extent
+ /// true if item was found in an extent, false otherwise
+ public bool GetStart(ushort item, out ushort start)
+ {
+ start = 0;
+ foreach(Tuple extent in
+ backend.Where(extent => item >= extent.Item1 && item <= extent.Item2))
+ {
+ start = extent.Item1;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Filters.cs b/Filters.cs
new file mode 100644
index 0000000..67a530d
--- /dev/null
+++ b/Filters.cs
@@ -0,0 +1,108 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : Filters.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Filters.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Enumerates all filters and instantiates the correct one.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using DiscImageChef.CommonTypes.Interfaces;
+using DiscImageChef.Console;
+
+namespace DiscImageChef.CommonTypes
+{
+ public class FiltersList
+ {
+ public SortedDictionary Filters;
+
+ ///
+ /// Fills the list of all known filters
+ ///
+ public FiltersList()
+ {
+ Assembly assembly = Assembly.Load("DiscImageChef.Filters");
+ Filters = new SortedDictionary();
+
+ foreach(Type type in assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IFilter))))
+ try
+ {
+ IFilter filter = (IFilter)type.GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { });
+ if(filter != null && !Filters.ContainsKey(filter.Name.ToLower()))
+ Filters.Add(filter.Name.ToLower(), filter);
+ }
+ catch(Exception exception) { DicConsole.ErrorWriteLine("Exception {0}", exception); }
+ }
+
+ ///
+ /// Gets the filter that allows to read the specified path
+ ///
+ /// Path
+ /// The filter that allows reading the specified path
+ public IFilter GetFilter(string path)
+ {
+ try
+ {
+ IFilter noFilter = null;
+ foreach(IFilter filter in Filters.Values)
+ if(filter.Id != new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
+ {
+ if(!filter.Identify(path)) continue;
+
+ IFilter foundFilter =
+ (IFilter)filter.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { });
+
+ foundFilter?.Open(path);
+
+ if(foundFilter?.IsOpened() == true) return foundFilter;
+ }
+ else
+ noFilter = filter;
+
+ if(!noFilter?.Identify(path) == true) return noFilter;
+
+ noFilter?.Open(path);
+
+ return noFilter;
+ }
+ catch(IOException) { return null; }
+ }
+
+ ///
+ /// Gets all known filters
+ ///
+ /// Known filters
+ public SortedDictionary GetFiltersList()
+ {
+ return Filters;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IChecksum.cs b/Interfaces/IChecksum.cs
new file mode 100644
index 0000000..ac56506
--- /dev/null
+++ b/Interfaces/IChecksum.cs
@@ -0,0 +1,60 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : IChecksum.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Checksums.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Provides an interface for implementing checksums and hashes.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+namespace DiscImageChef.CommonTypes.Interfaces
+{
+ public interface IChecksum
+ {
+ ///
+ /// Updates the hash with data.
+ ///
+ /// Data buffer.
+ /// Length of buffer to hash.
+ void Update(byte[] data, uint len);
+
+ ///
+ /// Updates the hash with data.
+ ///
+ /// Data buffer.
+ void Update(byte[] data);
+
+ ///
+ /// Returns a byte array of the hash value.
+ ///
+ byte[] Final();
+
+ ///
+ /// Returns a hexadecimal representation of the hash value.
+ ///
+ string End();
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IFilesystem.cs b/Interfaces/IFilesystem.cs
new file mode 100644
index 0000000..132d335
--- /dev/null
+++ b/Interfaces/IFilesystem.cs
@@ -0,0 +1,72 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : IFilesystem.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Filesystem plugins.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Interface for filesystem plugins.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Text;
+using Schemas;
+
+namespace DiscImageChef.CommonTypes.Interfaces
+{
+ ///
+ /// Interface to implement filesystem plugins.
+ ///
+ public interface IFilesystem
+ {
+ Encoding Encoding { get; }
+ /// Plugin name.
+ string Name { get; }
+ /// Plugin UUID.
+ Guid Id { get; }
+ ///
+ /// Information about the filesystem as expected by CICM Metadata XML
+ ///
+ /// Information about the filesystem as expected by CICM Metadata XML
+ FileSystemType XmlFsType { get; }
+
+ ///
+ /// Identifies the filesystem in the specified LBA
+ ///
+ /// Disk image.
+ /// Partition.
+ /// true, if the filesystem is recognized, false otherwise.
+ bool Identify(IMediaImage imagePlugin, Partition partition);
+
+ ///
+ /// Gets information about the identified filesystem.
+ ///
+ /// Disk image.
+ /// Partition.
+ /// Filesystem information.
+ /// Which encoding to use for this filesystem.
+ void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding);
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IFilter.cs b/Interfaces/IFilter.cs
new file mode 100644
index 0000000..9af7c2a
--- /dev/null
+++ b/Interfaces/IFilter.cs
@@ -0,0 +1,172 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : IFilter.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Filters.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Defines the interface for a Filter.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.IO;
+
+namespace DiscImageChef.CommonTypes.Interfaces
+{
+ public interface IFilter
+ {
+ /// Descriptive name of the plugin
+ string Name { get; }
+ /// Unique UUID of the plugin
+ Guid Id { get; }
+
+ ///
+ /// Closes all opened streams.
+ ///
+ void Close();
+
+ ///
+ /// Gets the path used to open this filter.
+ /// UNIX: /path/to/archive.zip/path/to/file.bin => /path/to/archive.zip/path/to/file.bin
+ /// Windows: C:\path\to\archive.zip\path\to\file.bin => C:\path\to\archive.zip\path\to\file.bin
+ ///
+ /// Path used to open this filter.
+ string GetBasePath();
+
+ ///
+ /// Gets creation time of file referenced by this filter.
+ ///
+ /// The creation time.
+ DateTime GetCreationTime();
+
+ ///
+ /// Gets length of this filter's data fork.
+ ///
+ /// The data fork length.
+ long GetDataForkLength();
+
+ ///
+ /// Gets a stream to access the data fork contents.
+ ///
+ /// The data fork stream.
+ Stream GetDataForkStream();
+
+ ///
+ /// Gets the filename for the file referenced by this filter.
+ /// UNIX: /path/to/archive.zip/path/to/file.bin => file.bin
+ /// Windows: C:\path\to\archive.zip\path\to\file.bin => file.bin
+ ///
+ /// The filename.
+ string GetFilename();
+
+ ///
+ /// Gets last write time of file referenced by this filter.
+ ///
+ /// The last write time.
+ DateTime GetLastWriteTime();
+
+ ///
+ /// Gets length of file referenced by ths filter.
+ ///
+ /// The length.
+ long GetLength();
+
+ ///
+ /// Gets full path to file referenced by this filter. If it's an archive, it's the path inside the archive.
+ /// UNIX: /path/to/archive.zip/path/to/file.bin => /path/to/file.bin
+ /// Windows: C:\path\to\archive.zip\path\to\file.bin => \path\to\file.bin
+ ///
+ /// The path.
+ string GetPath();
+
+ ///
+ /// Gets path to parent folder to the file referenced by this filter. If it's an archive, it's the full path to the
+ /// archive itself.
+ /// UNIX: /path/to/archive.zip/path/to/file.bin => /path/to/archive.zip
+ /// Windows: C:\path\to\archive.zip\path\to\file.bin => C:\path\to\archive.zip
+ ///
+ /// The parent folder.
+ string GetParentFolder();
+
+ ///
+ /// Gets length of this filter's resource fork.
+ ///
+ /// The resource fork length.
+ long GetResourceForkLength();
+
+ ///
+ /// Gets a stream to access the resource fork contents.
+ ///
+ /// The resource fork stream.
+ Stream GetResourceForkStream();
+
+ ///
+ /// Returns true if the file referenced by this filter has a resource fork
+ ///
+ bool HasResourceFork();
+
+ ///
+ /// Identifies if the specified path contains data recognizable by this filter instance
+ ///
+ /// Path.
+ bool Identify(string path);
+
+ ///
+ /// Identifies if the specified stream contains data recognizable by this filter instance
+ ///
+ /// Stream.
+ bool Identify(Stream stream);
+
+ ///
+ /// Identifies if the specified buffer contains data recognizable by this filter instance
+ ///
+ /// Buffer.
+ bool Identify(byte[] buffer);
+
+ ///
+ /// Returns true if the filter has a file/stream/buffer currently opened and no
+ /// has been issued.
+ ///
+ bool IsOpened();
+
+ ///
+ /// Opens the specified path with this filter instance
+ ///
+ /// Path.
+ void Open(string path);
+
+ ///
+ /// Opens the specified stream with this filter instance
+ ///
+ /// Stream.
+ void Open(Stream stream);
+
+ ///
+ /// Opens the specified buffer with this filter instance
+ ///
+ /// Buffer.
+ void Open(byte[] buffer);
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IFloppyImage.cs b/Interfaces/IFloppyImage.cs
new file mode 100644
index 0000000..b392df3
--- /dev/null
+++ b/Interfaces/IFloppyImage.cs
@@ -0,0 +1,129 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : IFloppyImage.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Disc image plugins.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Defines interface to be implemented by floppy image plugins.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using DiscImageChef.CommonTypes.Enums;
+using DiscImageChef.CommonTypes.Structs;
+
+namespace DiscImageChef.CommonTypes.Interfaces
+{
+ ///
+ /// Abstract class to implement disk image reading plugins that can contain floppy images.
+ /// This interface is needed because floppy formatting characteristics are not necesarily compatible with the whole.
+ /// LBA-oriented interface is defined by .
+ /// All data returned by these methods is already decoded from its corresponding bitstream.
+ ///
+ public interface IFloppyImage : IMediaImage
+ {
+ ///
+ /// Floppy info, contains information about physical characteristics of floppy, like size, bitrate, track density,
+ /// etc...
+ ///
+ FloppyInfo FloppyInfo { get; }
+
+ ///
+ /// Reads a sector's user data.
+ ///
+ ///
+ /// If is one of the duplicates is returned
+ /// randomly.
+ /// If is or
+ /// random data is returned.
+ /// If is null is returned.
+ /// Otherwise, whatever is in the sector is returned.
+ ///
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ /// Logical sector ID.
+ /// Status of request.
+ byte[] ReadSector(ushort track, byte head, ushort sector, out FloppySectorStatus status);
+
+ ///
+ /// Reads a sector's tag.
+ ///
+ ///
+ /// If is one of the duplicates is returned
+ /// randomly.
+ /// If is or
+ /// random data is returned.
+ /// If is null is returned.
+ /// Otherwise, whatever tag is in the sector is returned.
+ ///
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ /// Logical sector ID.
+ /// Status of request.
+ byte[] ReadSectorTag(ushort track, byte head, ushort sector, out FloppySectorStatus status, SectorTagType tag);
+
+ ///
+ /// Reads a whole track. It includes all gaps, address marks, sectors data, etc.
+ ///
+ /// The track data.
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ byte[] ReadTrack(ushort track, byte head);
+
+ ///
+ /// Reads a sector's data including all tags, address mark, and so, in a format dependent of represented media.
+ ///
+ ///
+ /// If is one of the duplicates is returned
+ /// randomly.
+ /// If is or
+ /// random data is returned.
+ /// If is null is returned.
+ /// Otherwise, whatever is in the sector is returned.
+ ///
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ /// Logical sector ID.
+ /// Status of request.
+ byte[] ReadSectorLong(ushort track, byte head, ushort sector, out FloppySectorStatus status);
+
+ ///
+ /// Verifies a track.
+ ///
+ /// True if correct, false if incorrect, null if uncheckable.
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ bool? VerifyTrack(ushort track, byte head);
+
+ ///
+ /// Verifies a sector, relative to track.
+ ///
+ /// True if correct, false if incorrect, null if uncheckable.
+ /// Physical track (position of the heads over the floppy media, 0-based).
+ /// Physical head (0-based).
+ /// Logical sector ID.
+ /// Status of request.
+ bool? VerifySector(ushort track, byte head, ushort sector);
+ }
+}
\ No newline at end of file
diff --git a/Interfaces/IMediaImage.cs b/Interfaces/IMediaImage.cs
new file mode 100644
index 0000000..20ffa4e
--- /dev/null
+++ b/Interfaces/IMediaImage.cs
@@ -0,0 +1,257 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : IMediaImage.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Disc image plugins.
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Defines interface to be implemented by disc image plugins.
+//
+// --[ License ] --------------------------------------------------------------
+//
+// This library is free software; you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of the
+// License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, see .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2018 Natalia Portillo
+// ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using DiscImageChef.CommonTypes.Enums;
+using DiscImageChef.CommonTypes.Structs;
+using Schemas;
+
+namespace DiscImageChef.CommonTypes.Interfaces
+{
+ ///
+ /// Abstract class to implement disk image reading plugins.
+ ///
+ public interface IMediaImage
+ {
+ /// Image information
+ ImageInfo Info { get; }
+ /// Plugin name.
+ string Name { get; }
+ /// Plugin UUID.
+ Guid Id { get; }
+ ///
+ /// Gets the image format.
+ ///
+ /// The image format.
+ string Format { get; }
+ ///
+ /// Gets an array partitions. Typically only useful for optical disc
+ /// images where each track and index means a different partition, as
+ /// reads can be relative to them.
+ ///
+ /// The partitions.
+ List Partitions { get; }
+ ///
+ /// Gets the disc track extents (start, length).
+ ///
+ /// The track extents.
+ List