/// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="id"></param>
 /// <param name="stream"></param>
 /// <param name="start"></param>
 /// <param name="end"></param>
 /// <param name="queue"></param>
 /// <param name="imgFiles"></param>
 public ImageFilesThread(int id, BufferedStream stream, long start, long end, BlockingCollection <int> queue, ImageFiles imgFiles)
 {
     this.id       = id;
     this.stream   = stream;
     this.imgFiles = imgFiles;
     this.start    = start;
     this.end      = end; // inclusive
     this.queue    = queue;
 }
        /// <summary>
        /// Begins the process of removing image block from phone's memory by calling several methods of ImageFiles.
        /// </summary>
        /// <param name="filterResult">The blocks remianing after block hash filtering. It is modified to being free from any image blocks too, by the end of the method.</param>
        /// <param name="imageFiles">The image blocks that were previosuly located on the phone's memory.</param>
        public static FilterResult FilterOutImages(FilterResult filterResult, ImageFiles imageFiles)
        {
            List <ImageBlock> reduced = RemoveImages(imageFiles.ImageBlocks, filterResult);

            WorkerThread.write("Filtered {0} images", imageFiles.ImageBlocks.Count - reduced.Count);
            long oldFilteredCount = filterResult.FilteredBytesCount;

            filterResult = FilterImageBlocks(imageFiles, filterResult);
            WorkerThread.write("Filtered an additional {0} bytes", filterResult.FilteredBytesCount - oldFilteredCount);
            imageFiles.ImageBlocks = reduced;
            return(filterResult);
        }
        /// <summary>
        /// Calls methods to begin locating image blocks in the memory file.
        /// </summary>
        /// <param name="filePath">Path of the phone's memory file.</param>
        /// <returns>A list of image blocks present in the phone's memory.</returns>
        public static ImageFiles LocateImages(string filePath)
        {
            ImageFiles imageFiles = null;

            try {
                imageFiles = new ImageFiles(filePath);
                imageFiles.Process();
                imageFiles.Close();
            } catch (Exception ex) {
                WorkerThread.write("Error locating images: " + ex.Message);
            } finally {
                if (imageFiles != null)
                {
                    imageFiles.Close();
                }
                else
                {
                    imageFiles = new ImageFiles();
                }
            }
            return(imageFiles);
        }
        /// <summary>
        /// Called after two independant operations have been performed: finding
        /// images in the memory, and excluding memory blocks because their hashes
        /// were known. Here we further reduce the memory that we'll use for
        /// searching for fields by removing memory consumed by images.
        /// </summary>
        /// <param name="imageFiles">Locations of found memory files.</param>
        /// <param name="filterResult">The filtered memory blocks.</param>
        /// <returns>An updated filtered memory block object.</returns>
        private static FilterResult FilterImageBlocks(ImageFiles imageFiles, FilterResult filterResult)
        {
            int imgCount = imageFiles.ImageBlocks.Count;

            if (imgCount == 0)
            {
                // No images had been found: nothing to do.
                return(filterResult);
            }
            bool         foundOverlap            = false;
            List <Block> reducedUnfilteredBlocks = new List <Block>();

            // For each memory block, update it if it contains all or part of an image.
            foreach (Block block in filterResult.UnfilteredBlocks)
            {
                long blockStart = block.OffsetFile;
                long blockEnd   = blockStart + block.Length - 1; // inclusive
                bool modified   = false;
                int  indx       = 0;
                // Go through the images and see if one is contained in the
                // memory block.
                while (!modified && (indx < imgCount))
                {
                    long imgStart = imageFiles.ImageBlocks[indx].Offset;
                    if (blockEnd < imgStart)
                    {
                        // We can assume image locations are ordered, so we can
                        // stop looking. All subsequent images will start after
                        // this memory block. Move on to the next block.
                        break;
                    }
                    long imgEnd = imgStart + imageFiles.ImageBlocks[indx].Length - 1; // inclusive
                    if (blockStart > imgEnd)
                    {
                        // The image ends before the block starts.
                        indx++;
                        continue;
                    }
                    if (((blockStart >= imgStart) && (blockStart <= imgEnd)) ||
                        ((blockEnd >= imgStart) && (blockEnd <= imgEnd)) ||
                        ((imgStart >= blockStart) && (imgStart <= blockEnd)) ||
                        ((imgEnd >= blockStart) && (imgEnd <= blockEnd)))
                    {
                        // All or part of the image is within the memory block.
                        modified     = true;
                        foundOverlap = true;
                        List <Block> reduced = RemoveImageBlock(block, imageFiles.ImageBlocks[indx]);
                        if (reduced.Count == 1)
                        {
                            reducedUnfilteredBlocks.Add(reduced[0]);
                        }
                        else if (reduced.Count > 0)
                        {
                            reducedUnfilteredBlocks.AddRange(reduced);
                        }
                        // It's possible there are more images that overlap, but
                        // we'll get them in a recursive call.
                        break;
                    }
                    indx++;
                }
                if (!modified)
                {
                    reducedUnfilteredBlocks.Add(block);
                }
            }
            // If we didn't find any overlaps, we're done.
            if (!foundOverlap)
            {
                return(filterResult);
            }
            long unfilteredCount = 0;

            foreach (Block block in reducedUnfilteredBlocks)
            {
                unfilteredCount += block.Length;
            }
            long filteredCount = filterResult.FilteredBytesCount + (filterResult.UnfilteredBytesCount - unfilteredCount);
            // A block can have multiple images within it. We remove one image
            // at a time, so we recursively call this function to remove images
            // from updated blocks. It may not be the most efficient method,
            // but it's a little cleaner.
            FilterResult newFilterResult = new FilterResult
            {
                Duration             = filterResult.Duration,
                FilteredBytesCount   = filteredCount,
                UnfilteredBytesCount = unfilteredCount,
                UnfilteredBlocks     = reducedUnfilteredBlocks
            };

            return(FilterImageBlocks(imageFiles, newFilterResult));
        }
Exemple #5
0
        /// <summary>
        /// This is where all of the work is done to extract information from
        /// the phone's binary file.
        /// It calls methods for image block identification, removal, block hash filtering, field and record level Viterbi infrerence, postprocessing of results.
        /// </summary>
        private void Run()
        {
            bool          success     = false;
            PostProcessor postProcess = null;
            PhoneInfo     phoneInfo   = null;

            try
            {
                // Use the SHA1 of the binary file to identify it.
                _canAbort = true;
                StartStep(1);
                write("Calculating file SHA1");
                fileSha1 = DcUtils.CalculateFileSha1(this.filePath);
                if (_cancel)
                {
                    return;
                }
                NextStep(1);
                // We scan the file to locate images. This is done independent
                // of block hashes.
                write("Extracting graphical images");
#if LOADONLY || SKIPIMAGES
                ImageFiles imageFiles = new ImageFiles();
#else
                ImageFiles imageFiles = ImageFiles.LocateImages(this.filePath);
                if (_cancel)
                {
                    return;
                }
                _canAbort = false;
                write("Extracted {0} graphical images", imageFiles.ImageBlocks.Count);
#endif
                NextStep(2);
                if (_cancel)
                {
                    return;
                }
                // Load the block hashes into the DB (if they're not already
                // there).
                HashLoader.HashLoader hashloader = HashLoader.HashLoader.LoadHashesIntoDB(fileSha1, this.filePath, this.manufacturer,
                                                                                          this.model, this.note, this.doNotStoreHashes);
                if (_cancel || (hashloader == null))
                {
                    return;
                }
                int phoneId = hashloader.PhoneId;
#if LOADONLY
                _cancel = true;
                return;
#endif
                _canAbort = true;
                NextStep(3);
                if (_cancel)
                {
                    return;
                }
                // Identify block hashes that are already in the DB, which we
                // will then filter out.
                FilterResult filterResult = RunBlockHashFilter(fileSha1, phoneId, hashloader.GetAndForgetStoredHashes());
                hashloader = null;
                NextStep(4);
                // Since images were located before block hash filter, forget
                // about any image that overlaps a filtered block hash.
                write("Filtering image locations");
                //filterResult = ImageFiles.FilterOutImages(filterResult, imageFiles);
                //Dump_Filtered_Blocks(filterResult, filePath);
                NextStep(5);
                // Finally, we're ready to use the Viterbi state machine.
                // Start by identifying fields.
                ViterbiResult viterbiResultFields = RunViterbi(filterResult, fileSha1);
                // Allow garbage collection.
                filterResult.UnfilteredBlocks.Clear();
                NextStep(6);
                List <MetaField> addressBookEntries = new List <MetaField>();
                List <MetaField> callLogs           = new List <MetaField>();
                List <MetaField> sms = new List <MetaField>();
                // Second run of Viterbi, this time for records.
                //ViterbiResult viterbiResultRecord = RunMetaViterbi(viterbiResultFields,addressBookEntries,callLogs,sms);
                RunMetaViterbi(viterbiResultFields, addressBookEntries, callLogs, sms);
                viterbiResultFields = null;
                NextStep(7);
                // Perform post processing. This may remove some records.
                postProcess = new PostProcessor(callLogs, addressBookEntries, sms, imageFiles.ImageBlocks);
                success     = PerformPostProcessing(postProcess);
                NextStep(8);

                GTC_CSV_Writer wr = new GTC_CSV_Writer(this.metaResults, postProcess, filePath);
                wr.Write_CSV();
                wr.Write_Field_Paths(this.fieldPaths);

                // Finished.
                phoneInfo = new PhoneInfo(manufacturer, model, note, doNotStoreHashes);
                write("Finished work");
                FinishedStep(9);
            }
            finally
            {
                if (_cancel)
                {
                    MainForm.Program.EndWork(false, null, null, null);
                }
                else
                {
                    MainForm.Program.EndWork(success, postProcess, this.filePath, phoneInfo);
                }
            }
        }