CrystalMpq.Explorer.MainForm.InteractiveExtractNodes C# (CSharp) Method

InteractiveExtractNodes() private method

private InteractiveExtractNodes ( TreeNode nodes ) : void
nodes TreeNode
return void
        private void InteractiveExtractNodes(TreeNode[] nodes)
        {
            extractionSettingsDialog.AllowRecurse = true;

            if (extractionSettingsDialog.ShowDialog(this) != DialogResult.OK) return;

            // Save the settings now…
            Settings.Default.ExtractionDirectory = extractionSettingsDialog.DestinationDirectory;
            Settings.Default.ExtractionRecurse = extractionSettingsDialog.Recurse;
            Settings.Default.ExtractionOverwriteFiles = extractionSettingsDialog.OverwriteFiles;

            Settings.Default.Save();

            var directoryInfo = new DirectoryInfo(extractionSettingsDialog.DestinationDirectory);
            ulong totalSize = 0;
            int totalFileCount = 0;

            // Initialize the stack.
            extractionStack = extractionStack ?? new Stack<TreeNode>();
            extractionStack.Clear();

            // Proceed to a tree walk for each requested node, in order to compute total file count and total size
            {
                foreach (var node in nodes)
                {
                    var currentNode = node;
                    do
                    {
                        if (currentNode.Nodes.Count > 0 && (extractionSettingsDialog.Recurse || extractionStack.Count == 0))
                        {
                            extractionStack.Push(currentNode);
                            currentNode = currentNode.FirstNode;
                        }
                        else
                        {
                            var file = currentNode.Tag as MpqFile;

                            if (file != null)
                            {
                                totalSize += unchecked((ulong)file.Size);
                                checked { totalFileCount++; } // Maybe this will fail someday, but I don't think the current Win32 ListView can handle more than 2^31 nodes…
                            }

                            while (currentNode == null || (currentNode != node && (currentNode = currentNode.NextNode) == null) && extractionStack.Count > 0)
                                if ((currentNode = extractionStack.Pop()) != node)
                                    currentNode = currentNode.NextNode;
                        }
                    } while (currentNode != node);
                }
            }

            // TODO: Make something a little better…
            if (totalFileCount == 0) return;

            // Initialize the extraction progress dialog
            extractionProgressionDialog.TotalSize = totalSize;
            extractionProgressionDialog.ProcessedSize = 0;

            extractionProgressionDialog.TotalFileCount = totalFileCount;
            extractionProgressionDialog.ProcessedFileCount = 0;

            extractionProgressionDialog.CurrentFileName = null;

            // Proceed to a tree walk for each requested node, but this time for doing real work
            // The extraction will be done on a separate thread, with progress displayed by the modal dialog
            extractionProgressionDialog.ShowDialog
            (
                this,
                (dialog, state) =>
                {
                    var buffer = new byte[4096];
                    int extractedFileCount = 0;

                    foreach (var node in nodes)
                    {
                        string directoryPhysicalPath = directoryInfo.FullName;
                        var currentNode = node;
                        do
                        {
                            if (currentNode.Nodes.Count > 0 && (extractionSettingsDialog.Recurse || extractionStack.Count == 0))
                            {
                                // Store the relative path into the tag, which should be null for directories…
                                currentNode.Tag = directoryPhysicalPath;
                                directoryPhysicalPath = Path.Combine(directoryPhysicalPath, currentNode.Text);

                                if (!Directory.Exists(directoryPhysicalPath))
                                    try { Directory.CreateDirectory(directoryPhysicalPath); }
                                    catch (Exception ex)
                                    {
                                        dialog.ErrorDialog(ex.Message);
                                        return;
                                    }

                                extractionStack.Push(currentNode);
                                currentNode = currentNode.FirstNode;
                            }
                            else
                            {
                                var file = currentNode.Tag as MpqFile;

                                if (file != null)
                                {
                                    string filePhysicalPath = Path.Combine(directoryPhysicalPath, currentNode.Text);
                                    bool canExtract = false;

                                    dialog.UpdateFileInformation(extractedFileCount + 1, file.Name);

                                    if (extractionSettingsDialog.OverwriteFiles || !File.Exists(filePhysicalPath)) canExtract = true;
                                    else
                                    {
                                        switch (dialog.AskForOverwrite(currentNode.Text, directoryPhysicalPath, unchecked((ulong)file.Size)))
                                        {
                                            case DialogResult.Yes: canExtract = true; break;
                                            case DialogResult.No: canExtract = false; break;
                                            case DialogResult.Cancel: return;
                                        }
                                    }

                                    if (canExtract)
                                    {
                                        try
                                        {
                                            using (var inputStream = file.Open())
                                            using (var outputStream = File.OpenWrite(filePhysicalPath))
                                            {
                                                int byteCounter = 0;
                                                int length;

                                                do
                                                {
                                                    length = inputStream.Read(buffer, 0, 4096);
                                                    outputStream.Write(buffer, 0, length);
                                                    if ((byteCounter += length) >= 0x100000)
                                                    {
                                                        dialog.ProcessedSize += 0x100000UL;
                                                        byteCounter -= 0x100000;
                                                    }
                                                }
                                                while (length == 4096);

                                                if (byteCounter > 0) dialog.ProcessedSize += unchecked((ulong)byteCounter);
                                                extractedFileCount++;
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            ErrorDialog(ex.ToString());
                                            return;
                                        }
                                    }
                                    else
                                    {
                                        dialog.TotalSize = totalSize -= unchecked((ulong)file.Size);
                                        dialog.TotalFileCount = totalFileCount--;
                                    }
                                }

                                while (currentNode == null || (currentNode != node && (currentNode = currentNode.NextNode) == null) && extractionStack.Count > 0)
                                {
                                    currentNode = extractionStack.Pop();
                                    directoryPhysicalPath = currentNode.Tag as string;
                                    currentNode.Tag = null; // Clean the tag when no longer needed

                                    if (currentNode != node)
                                        currentNode = currentNode.NextNode;
                                }
                            }
                        } while (currentNode != node);
                    }
                }
            );
        }