diff --git a/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj b/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj
index b20970cb1..7f2ebf4a0 100644
--- a/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj
+++ b/DiscImageChef.Helpers/DiscImageChef.Helpers.csproj
@@ -45,6 +45,14 @@
+
+
+
+
+
+
+
+
@@ -58,6 +66,9 @@
LICENSE.LGPL
+
+
+
@@ -70,7 +81,7 @@
-
+
diff --git a/DiscImageChef.Helpers/Extents/ExtentsByte.cs b/DiscImageChef.Helpers/Extents/ExtentsByte.cs
new file mode 100644
index 000000000..f5e0dd5ff
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsByte.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsByte.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsByte
+ {
+ List> backend;
+
+ public ExtentsByte()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(byte start, byte end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(byte start, byte end, bool run)
+ {
+ byte realEnd;
+ if(run)
+ realEnd = (byte)(start + end - 1);
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(byte t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(byte item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsInt.cs b/DiscImageChef.Helpers/Extents/ExtentsInt.cs
new file mode 100644
index 000000000..096aa5f1d
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsInt.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsInt.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsInt
+ {
+ List> backend;
+
+ public ExtentsInt()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(int start, int end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(int start, int end, bool run)
+ {
+ int realEnd;
+ if(run)
+ realEnd = start + end - 1;
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(int t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(int item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsLong.cs b/DiscImageChef.Helpers/Extents/ExtentsLong.cs
new file mode 100644
index 000000000..dde1c4dc2
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsLong.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsLong.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsLong
+ {
+ List> backend;
+
+ public ExtentsLong()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(long start, long end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(long start, long end, bool run)
+ {
+ long realEnd;
+ if(run)
+ realEnd = start + end - 1;
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(long t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(long item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsSByte.cs b/DiscImageChef.Helpers/Extents/ExtentsSByte.cs
new file mode 100644
index 000000000..ec1c06083
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsSByte.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsSByte.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsSByte
+ {
+ List> backend;
+
+ public ExtentsSByte()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(sbyte start, sbyte end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(sbyte start, sbyte end, bool run)
+ {
+ sbyte realEnd;
+ if(run)
+ realEnd = (sbyte)(start + end - 1);
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(sbyte t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(sbyte item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsShort.cs b/DiscImageChef.Helpers/Extents/ExtentsShort.cs
new file mode 100644
index 000000000..70f9c7e78
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsShort.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsShort.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsShort
+ {
+ List> backend;
+
+ public ExtentsShort()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(short start, short end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(short start, short end, bool run)
+ {
+ short realEnd;
+ if(run)
+ realEnd = (short)(start + end - 1);
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(short t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(short item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsUInt.cs b/DiscImageChef.Helpers/Extents/ExtentsUInt.cs
new file mode 100644
index 000000000..a91ef9ad1
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsUInt.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsUInt.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsUInt
+ {
+ List> backend;
+
+ public ExtentsUInt()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(uint start, uint end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(uint start, uint end, bool run)
+ {
+ uint realEnd;
+ if(run)
+ realEnd = start + end - 1;
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(uint t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(uint item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsULong.cs b/DiscImageChef.Helpers/Extents/ExtentsULong.cs
new file mode 100644
index 000000000..95d0051da
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsULong.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsULong.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsULong
+ {
+ List> backend;
+
+ public ExtentsULong()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(ulong start, ulong end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(ulong start, ulong end, bool run)
+ {
+ ulong realEnd;
+ if(run)
+ realEnd = start + end - 1;
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(ulong t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(ulong item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}
diff --git a/DiscImageChef.Helpers/Extents/ExtentsUShort.cs b/DiscImageChef.Helpers/Extents/ExtentsUShort.cs
new file mode 100644
index 000000000..3950aaa3c
--- /dev/null
+++ b/DiscImageChef.Helpers/Extents/ExtentsUShort.cs
@@ -0,0 +1,200 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : ExtentsUShort.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extents
+{
+ public class ExtentsUShort
+ {
+ List> backend;
+
+ public ExtentsUShort()
+ {
+ backend = new List>();
+ }
+
+ public int Count { get { return backend.Count; } }
+
+ 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)
+ {
+ 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();
+ }
+
+ public void Add(ushort start, ushort end)
+ {
+ Add(start, end, false);
+ }
+
+ public void Add(ushort start, ushort end, bool run)
+ {
+ ushort realEnd;
+ if(run)
+ realEnd = (ushort)(start + end - 1);
+ else
+ realEnd = end;
+
+ // TODO: Optimize this
+ for(ushort t = start; t <= realEnd; t++)
+ Add(t);
+ }
+
+ public bool Contains(ushort item)
+ {
+ foreach(Tuple extent in backend)
+ if(item >= extent.Item1 && item <= extent.Item2)
+ return true;
+ return false;
+ }
+
+ public void Clear()
+ {
+ backend.Clear();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ public Tuple[] ToArray()
+ {
+ return backend.ToArray();
+ }
+ }
+}