diff --git a/DiscImageChef.DiscImages/PartClone.cs b/DiscImageChef.DiscImages/PartClone.cs index 4eaa56870..285042894 100644 --- a/DiscImageChef.DiscImages/PartClone.cs +++ b/DiscImageChef.DiscImages/PartClone.cs @@ -39,6 +39,7 @@ using System.Linq; using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.Filters; +using Extents; namespace DiscImageChef.DiscImages { @@ -112,6 +113,9 @@ namespace DiscImageChef.DiscImages const uint MaxCacheSize = 16777216; uint maxCachedSectors = MaxCacheSize / 512; + ExtentsULong extents; + Dictionary extentsOff; + public PartClone() { Name = "PartClone disk image"; @@ -204,6 +208,42 @@ namespace DiscImageChef.DiscImages dataOff = stream.Position; DicConsole.DebugWriteLine("PartClone plugin", "pHdr.dataOff = {0}", dataOff); + DicConsole.DebugWriteLine("PartClone plugin", "Filling extents"); + DateTime start = DateTime.Now; + extents = new ExtentsULong(); + extentsOff = new Dictionary(); + bool current = byteMap[0] > 0; + ulong blockOff = 0; + ulong extentStart = 0; + + for(ulong i = 1; i < pHdr.totalBlocks; i++) + { + bool next = byteMap[i] > 0; + + // Flux + if(next != current) + { + // Next is used + if(next) + { + extentStart = i; + extentsOff.Add(i, ++blockOff); + } + else + { + extents.Add(extentStart, i); + extentsOff.TryGetValue(extentStart, out ulong foo); + } + } + + if(next && current) + blockOff++; + + current = next; + } + DateTime end = DateTime.Now; + DicConsole.DebugWriteLine("PartClone plugin", "Took {0} seconds to fill extents", (end - start).TotalSeconds); + sectorCache = new Dictionary(); ImageInfo.imageCreationTime = imageFilter.GetCreationTime(); @@ -219,16 +259,11 @@ namespace DiscImageChef.DiscImages return true; } - // TODO: Find a way to optimize this, it's insanely slow! ulong BlockOffset(ulong sectorAddress) { - ulong blockOff = 0; - for(ulong i = 0; i < sectorAddress; i++) - { - if(byteMap[i] > 0) - blockOff++; - } - return blockOff; + extents.GetStart(sectorAddress, out ulong extentStart); + extentsOff.TryGetValue(extentStart, out ulong extentStartingOffset); + return extentStartingOffset + (sectorAddress - extentStart); } public override byte[] ReadSector(ulong sectorAddress) diff --git a/DiscImageChef.DiscImages/Partimage.cs b/DiscImageChef.DiscImages/Partimage.cs index 02e46a65f..afc193d61 100644 --- a/DiscImageChef.DiscImages/Partimage.cs +++ b/DiscImageChef.DiscImages/Partimage.cs @@ -40,6 +40,7 @@ using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.Filters; using System.Text; +using Extents; namespace DiscImageChef.DiscImages { @@ -269,6 +270,9 @@ namespace DiscImageChef.DiscImages const uint MaxCacheSize = 16777216; uint maxCachedSectors = MaxCacheSize / 512; + ExtentsULong extents; + Dictionary extentsOff; + public Partimage() { Name = "Partimage disk image"; @@ -475,6 +479,42 @@ namespace DiscImageChef.DiscImages if(!magic.Equals(MAGIC_BEGIN_TAIL)) throw new ImageNotSupportedException("Cannot find tail. Multiple volumes are not supported or image is corrupt."); + DicConsole.DebugWriteLine("Partimage plugin", "Filling extents"); + DateTime start = DateTime.Now; + extents = new ExtentsULong(); + extentsOff = new Dictionary(); + bool current = (bitmap[0] & 1 << (int)(0 % 8)) != 0; + ulong blockOff = 0; + ulong extentStart = 0; + + for(ulong i = 1; i <= localHeader.qwBlocksCount; i++) + { + bool next = (bitmap[i / 8] & 1 << (int)(i % 8)) != 0; + + // Flux + if(next != current) + { + // Next is used + if(next) + { + extentStart = i; + extentsOff.Add(i, ++blockOff); + } + else + { + extents.Add(extentStart, i); + extentsOff.TryGetValue(extentStart, out ulong foo); + } + } + + if(next && current) + blockOff++; + + current = next; + } + DateTime end = DateTime.Now; + DicConsole.DebugWriteLine("Partimage plugin", "Took {0} seconds to fill extents", (end - start).TotalSeconds); + sectorCache = new Dictionary(); ImageInfo.imageCreationTime = dateCreate; @@ -492,21 +532,11 @@ namespace DiscImageChef.DiscImages return true; } - bool IsEmpty(ulong sectorAddress) - { - return (bitmap[sectorAddress / 8] & 1 << (int)(sectorAddress % 8)) == 0; - } - - // TODO: Find a way to optimize this, it's insanely slow! ulong BlockOffset(ulong sectorAddress) { - ulong blockOff = 0; - for(ulong i = 0; i < sectorAddress; i++) - { - if(!IsEmpty(i)) - blockOff++; - } - return blockOff; + extents.GetStart(sectorAddress, out ulong extentStart); + extentsOff.TryGetValue(extentStart, out ulong extentStartingOffset); + return extentStartingOffset + (sectorAddress - extentStart); } public override byte[] ReadSector(ulong sectorAddress) @@ -514,7 +544,7 @@ namespace DiscImageChef.DiscImages if(sectorAddress > ImageInfo.sectors - 1) throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress)); - if(IsEmpty(sectorAddress)) + if((bitmap[sectorAddress / 8] & 1 << (int)(sectorAddress % 8)) == 0) return new byte[ImageInfo.sectorSize]; byte[] sector;