/// <summary> /// Each thread creates its own list of ImageBlocks. This avoids locking /// but now we need to combine the lists into a single sorted list. Each /// thread's list is already sorted by offset. /// </summary> /// <param name="nThreads">Number of threads.</param> private void CollateList(int nThreads) { if (nThreads == 1) { ImageBlocks.AddRange(threadBlocks[0]); return; } // It's possible that we can have an image that overlaps with another // image found by separate threads. use the first image, which is // euqivalent to what would happen if we had a single thread. long prevEnd = -1; for (int n = 0; n < nThreads; n++) { for (int i = 0; i < threadBlocks[n].Count; i++) { ImageBlock ib = threadBlocks[n][i]; if (ib.Offset > prevEnd) { ImageBlocks.Add(ib); prevEnd = ib.Offset + ib.Length - 1; } } } }
/// <summary> /// Given a block of memory that all or partially contains an image, /// reduce the memory to not contain the image. /// </summary> /// <param name="block">Block of memory</param> /// <param name="imageBlock">Image location and length in memory.</param> /// <returns>A list of new blocks that exclude the image.</returns> private static List <Block> RemoveImageBlock(Block block, ImageBlock imageBlock) { long blockStart = block.OffsetFile; long blockEnd = blockStart + block.Length - 1; // inclusive long imgStart = imageBlock.Offset; long imgEnd = imgStart + imageBlock.Length - 1; // inclusive if ((blockStart >= imgStart) && (blockEnd <= imgEnd)) { // Simple case: block entirely within the image. return(new List <Block>()); } List <Block> reduced = new List <Block>(); Block blockBefore = null; Block blockAfter = null; if ((imgStart >= blockStart) && (imgEnd <= blockEnd)) { // Image entirely within the block. Can have memory before and // after the image. May need to split memory block into two // blocks. int len = 0; if (blockStart < imgStart) { // Have memory before. len = (int)(imgStart - blockStart); byte[] data = null; if (block.Bytes != null) { data = new byte[len]; Array.Copy(block.Bytes, 0, data, 0, len); } blockBefore = new Block { OffsetFile = blockStart, Length = len, Bytes = data }; } // Have memory after. if (imgEnd < blockEnd) { long fileOffset = imgEnd + 1; int arrayOffset = len + imageBlock.Length; len = (int)(blockEnd - imgEnd); byte[] data = null; if (block.Bytes != null) { data = new byte[len]; Array.Copy(block.Bytes, arrayOffset, data, 0, len); } blockAfter = new Block { OffsetFile = fileOffset, Length = len, Bytes = data }; } } else if (blockStart < imgStart) { // Block overlaps the image at the higher end of the memory. int len = (int)(imgStart - blockStart); byte[] data = null; if (block.Bytes != null) { data = new byte[len]; Array.Copy(block.Bytes, 0, data, 0, len); } blockBefore = new Block { OffsetFile = blockStart, Length = len, Bytes = data }; } else if (imgEnd < blockEnd) { // Block overlaps the image at the lower end of the memory. long fileOffset = imgEnd + 1; int len = (int)(blockEnd - imgEnd); byte[] data = null; if (block.Bytes != null) { data = new byte[len]; int arrayOffset = block.Length - len; Array.Copy(block.Bytes, arrayOffset, data, 0, len); } blockAfter = new Block { OffsetFile = fileOffset, Length = len, Bytes = data }; } if (blockBefore != null) { reduced.Add(blockBefore); } if (blockAfter != null) { reduced.Add(blockAfter); } return(reduced); }
/// <summary> /// Called by a thread when it discovers an image. Adds the image to a list. /// </summary> /// <param name="block">ImageBlock object represeting the located image.</param> /// <param name="id">Xero-based index identifying the thread.</param> public void AddBlock(ImageBlock block, int id) { threadBlocks[id].Add(block); }